Extraiga el índice de primer elemento único en una gran matriz en SWIFT -- performance campo con strings campo con programming-challenge campo con swift campo con set camp codereview Relacionados El problema

Extract index of first unique element in large array in Swift


3
vote

problema

Español

Estoy usando el siguiente código para devolver El primer índice de un carácter único en un gran skew.CalibrationDate.Date == (from skew2 in db.Skew where skew2.CalibrationDate.Date <= date.Date select skew2.CalibrationDate).Max() 6 . Funciona bien hasta que llego a las cuerdas grandes, donde salga.

¿Hay una manera más rápida de lograr el objetivo de obtener una retención del índice de carácter único usando skew.CalibrationDate.Date == (from skew2 in db.Skew where skew2.CalibrationDate.Date <= date.Date select skew2.CalibrationDate).Max() 7 ?

actualización

La cadena contiene 25,000 caracteres. Refactoré la publicación original para extraer los caracteres únicos, luego el ciclo a través de la matriz y ver si cada índice está contenido dentro de la matriz 998877666655443318 . Es un poco más rápido, pero no lo suficientemente rápido como para pasar el temporizador de leetcode.

  skew.CalibrationDate.Date == (from skew2 in db.Skew                                where skew2.CalibrationDate.Date <= date.Date                                select skew2.CalibrationDate).Max() 9  
Original en ingles

I'm using the following code to return the first index of a unique character in a large String. It works fine until I get to large strings, where it times out.

Is there a faster way to accomplish the goal of getting a hold of the unique character's index using NSCountedSet?

Update

The string contains 25,000 characters. I refactored the original post to extract the unique chars, then cycle through the array and see if each index is contained within the uniqueChar array. It's a little faster, but not fast enough to pass Leetcode's timer.

func firstUniqChar(_ s: String) -> Int {     guard Set(s.characters).count > 0 && s.characters.count > 0 else { return -1 }     let stringArray = s.characters.map({String($0)})      let countedSet = NSCountedSet(array: stringArray)      var uniqueChars: [String] = []      for char in countedSet {         if countedSet.count(for: char) == 1 {             uniqueChars.append(String(describing: char))         }     }      for index in 0..<stringArray.count {         if uniqueChars.contains(stringArray[index]) {             return index         }     }      return -1 } 
              
   
   

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

tu prueba inicial

  guard Set(s.characters).count > 0 && s.characters.count > 0 else { return -1 }   

no es necesario, el código restante ya maneja el caso de un cuerda vacía.

Determinar los caracteres únicos de countedSet puede ser sencilla con una operación de filtro en lugar de un bucle for-bucle:

  let uniqueChars = countedSet.filter {      countedSet.count(for: $0) == 1 } as! [String]   

Pero en realidad esa lista no es necesaria en absoluto porque todo lo que tienes que hacer En el bucle final es encontrar el primer carácter que tiene un conteo. de uno. La función se ve así:

  func firstUniqChar(_ s: String) -> Int {     let stringArray = s.characters.map({String($0)})     let countedSet = NSCountedSet(array: stringArray)     for index in 0..<stringArray.count {         if countedSet.count(for: stringArray[index]) == 1 {             return index         }     }     return -1 }   

que es más sencillo y un poco más rápido que el original.

Esto puede mejorarse evitando la conversión de cada personaje a una cadena y la matriz, y operando en el UTF-16 Vista de la cadena dada directamente:

  func firstUniqChar(_ s: String) -> Int {     let countedSet = NSCountedSet()     for char in s.utf16 {         countedSet.add(char)     }     for (index, char) in s.utf16.enumerated() {         if countedSet.count(for: char) == 1 {             return index         }     }     return -1 }   

NSCountedSet es de la biblioteca de la Fundación y trabaja con NSObject instancias. El método anterior funciona porque el UInt16 El valor se envuelve automáticamente en un objeto cuando añadido al conjunto contado. Esta conversión puede ser evitada por utilizando un diccionario nativo swift en su lugar, lo que hace que la Código MUCHO FASTER:

  func firstUniqChar(_ s: String) -> Int {     // Map from character to number of occurrences:     var counts: [UInt16: Int] = [:]      for char in s.utf16 {         if let cnt = counts[char] {             counts[char] = cnt + 1         } else {             counts[char] = 1         }     }     for (index, char) in s.utf16.enumerated() {         if counts[char]! == 1 {             return index         }     }     return -1 }   

puntos de referencia. Código de prueba:

  let s = String(repeating: "abcdefghijklmnopqrstuvwxy", count: 1000) + "z" + String(repeating: "abcdefghijklmnopqrstuvwxy", count: 1000) print(s.characters.count) // 50001  let start = Date() let i = firstUniqChar(s) let end = Date()  print(i, end.timeIntervalSince(start))   

Resultados (en un IMAC Intel Core I5 ​​de 3.5 GHz, compilado en la versión Configuración):

 Su función original: 0.084 seg. Primera mejora: 0.058 seg. Segunda Mejora: 0.014 seg. Última función: 0.003 seg. 

El último método puede ser escrito más compacto como

  countedSet0  

sin cambiar el rendimiento.

 

Your initial test

guard Set(s.characters).count > 0 && s.characters.count > 0 else { return -1 } 

is not needed, the remaining code already handles the case of an empty string.

Determining the unique characters from countedSet can simpler be done with a filter operation instead of a for-loop:

let uniqueChars = countedSet.filter {      countedSet.count(for: $0) == 1 } as! [String] 

But actually that list is not needed at all because all you have to do in the final loop is to find the first character which has a count of one. The function then looks like this:

func firstUniqChar(_ s: String) -> Int {     let stringArray = s.characters.map({String($0)})     let countedSet = NSCountedSet(array: stringArray)     for index in 0..<stringArray.count {         if countedSet.count(for: stringArray[index]) == 1 {             return index         }     }     return -1 } 

which is simpler and a bit faster than the original one.

This can further be improved by avoiding the conversion of each character to a string and the array, and operating on the UTF-16 view of the given string directly:

func firstUniqChar(_ s: String) -> Int {     let countedSet = NSCountedSet()     for char in s.utf16 {         countedSet.add(char)     }     for (index, char) in s.utf16.enumerated() {         if countedSet.count(for: char) == 1 {             return index         }     }     return -1 } 

NSCountedSet is from the Foundation library and works with NSObject instances. The previous method works because the UInt16 value is automatically wrapped into an object when added to the counted set. This conversion can be avoided by using a native Swift dictionary instead, which makes the code much faster:

func firstUniqChar(_ s: String) -> Int {     // Map from character to number of occurrences:     var counts: [UInt16: Int] = [:]      for char in s.utf16 {         if let cnt = counts[char] {             counts[char] = cnt + 1         } else {             counts[char] = 1         }     }     for (index, char) in s.utf16.enumerated() {         if counts[char]! == 1 {             return index         }     }     return -1 } 

Benchmarks. Test code:

let s = String(repeating: "abcdefghijklmnopqrstuvwxy", count: 1000) + "z" + String(repeating: "abcdefghijklmnopqrstuvwxy", count: 1000) print(s.characters.count) // 50001  let start = Date() let i = firstUniqChar(s) let end = Date()  print(i, end.timeIntervalSince(start)) 

Results (on a 3.5 GHz Intel Core i5 iMac, compiled in Release configuration):

 Your original function:  0.084 sec First improvement:       0.058 sec Second improvement:      0.014 sec Last function:           0.003 sec 

The last method can be more compactly written as

func firstUniqChar(_ s: String) -> Int {     // Map from character to number of occurrences:     var counts: [UInt16: Int] = [:]      for char in s.utf16 {         counts[char] = (counts[char] ?? 0) + 1     }      let index = s.utf16.enumerated()         .first(where: { counts[$0.element]! == 1 })?         .offset     return index ?? -1 } 

without changing the performance.

 
 
 
 

Relacionados problema

3  Encontrar la cantidad de formas de particionar {1,2, ..., n} en P1 y P2 de tal manera que suma (P1) == SUM (P2)  ( Finding the number of ways to partition 1 2 n into p1 and p2 such that s ) 
Estoy tratando de escribir un algoritmo de espacio y tiempo eficiente para calcular la cantidad de formas de particionar un conjunto de enteros {1, 2, ..., n}...

1  Set persistente (árbol negro rojo) - seguimiento  ( Persistent set red black tree follow up ) 
Seguimiento de esta pregunta cosas que cambié: arreglado algunos typos variables y métodos renombrados a nombres más descriptivos. (Eliminado 1 varia...

1  Optimización divisible de subconjunto más grande  ( Largest divisible subset optimization ) 
Entonces, esta es mi solución al siguiente problema de leetcode: https: // leetcode .com / problemas / mayor-divisible-subconjunto / descripción / ¿Cómo p...

1  Posibles combinaciones de letras de una almohadilla de marcación en tiempo lineal utilizando un enfoque recursivo  ( Possible letter combinations of a dial pad in linear time using a recursive appr ) 
complejidad de tiempo: Camino la matriz de llaves inzagonadas inicial que representan el número O (n) hacia atrás. Luego hago un paseo interno de la matriz de...

2  Set persistente (árbol negro rojo)  ( Persistent set red black tree ) 
Esta es una estructura de datos parcialmente persistente utilizando un árbol negro rojo. Se copiarán $ O (LG (N)) $ artículos para cada operación eliminar o...

2  Disyointset con O (1) Encuentre y o (1) Unión amortizada  ( Disjointset with o1 find and o1 amortised union ) 
¿Este código supera la implementación común con la compresión de ruta y la unidad por rango? Todavía estoy de acuerdo con una revisión. github import j...

7  Convierta una lista de conjuntos en la lista mínima de conjuntos que no sean intersectores  ( Convert a list of sets into the minimum list of non intersecting sets ) 
Tengo una lista de conjuntos. Los mismos elementos pueden aparecer en varios conjuntos. Quiero transformar esto en una nueva lista de conjuntos donde: Ca...

11  Programa de chat "ai"  ( Ai chat program ) 
He lanzado este simple programa de chat, y mientras funciona. Creo que ciertamente podría usar alguna mejora. Así es como funciona. Obtenga la entrada del ...

3  Prueba para una matriz que es un subconjunto de otra matriz maestra  ( Test for an array being subset of another master array ) 
Estaba intentando construir una pequeña función de utilidad para verificar si una matriz es parte de otra matriz. Está probando si una matriz es un subconjunt...

7  Forma más rápida de comparar conjuntos genéricos  ( Faster way of comparing generic sets ) 
El siguiente método de extensión es el factor limitante en el desempeño de una solicitud que estoy desarrollando, según Visual Studio 2012 Performance Analysi...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos