ARTES #003
ARTES #003
ARTES es una actividad iniciada por
由左耳朵耗子--陈皓: Haga al menos una pregunta sobre el algoritmo leetcode cada semana, lea y comente al menos un artículo técnico en inglés, aprenda al menos una habilidad técnica y comparta un artículo con opiniones y pensamientos. (Es decir, Algoritmo, Revisión, Sugerencia y Compartir se denominan ARTS) y persisten durante al menos un año.
##ARTES 003
Este es el tercer artículo y está relativamente mal escrito. Espero que mejore cada vez más en el futuro.
Pregunta sobre el algoritmo del algoritmo
Algoritmo leetcode pregunta 151 Palabras inversas en una cadena (palabras inversas en una cadena) Podría ser: moderado
Given an input string, reverse the string word by word.
Example:
Input: "the sky is blue",
Output: "blue is sky the".
Note:
A word is defined as a sequence of non-space characters.
Input string may contain leading or trailing spaces. However, your reversed string should not contain leading or trailing spaces.
You need to reduce multiple spaces between two words to a single space in the reversed string.
Follow up: For C programmers, try to solve it in-place in O(1) space.
给定一个字符串,逐个翻转字符串中的每个单词。
示例:
输入: "the sky is blue",
输出: "blue is sky the".
说明:
无空格字符构成一个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶: 请选用C语言的用户尝试使用 O(1) 时间复杂度的原地解法。
Si no considera el problema del espacio, este algoritmo es relativamente simple. Voltee toda la cadena y luego voltee cada palabra. La dificultad de esta pregunta es cómo eliminar el exceso de espacios, incluidos los espacios al principio, los espacios al final y el exceso de espacios entre palabras. La implementación es la siguiente:
void ReverseString(char* str,int min,int max) {
int i = min;
int j = max;
while (i < j) {
char temp = * (str + i);
* (str + i) = * (str + j);
* (str + j) = temp;
i++;
j--;
}
}
//翻转字符串
void reverseWords(char *fdg) {
RemoveEmptyChar(fdg);
ReverseString(fdg,0,strlen(fdg) -1);
int i = 0;
int j = 0;
while (*(fdg + j)) {
if (*(fdg + j) == ' ') {
ReverseString(fdg,i,j-1);
i=j+1;
}
j++;
}
ReverseString(fdg,i,j-1);
}
//去掉空格
void RemoveEmptyChar(char* str) {
//先去掉尾部的空格
int j = strlen(str) -1;
while (*(str + j) == ' ') {
*(str + j) = '\0';
j--;
}
//去掉头部的空格
int i = 0;
while (*(str + i) == ' ') {
i++;
}
if(i > 0){
int count = 0;
while ((count < strlen(str) - i) && *(str +i + count)) {
*(str + count) = *(str +i + count);
count++;
}
*(str + count) = '\0';
}
//去掉中间的空格
int m = 0;
int flag = 0;
while (m < strlen(str)) {
if (*(str + m) == ' '){
flag++;
m++;
continue;
}
if (flag > 1) {
int count = 0;
while ((count < strlen(str) -m)) {
*(str + m - flag + 1 + count) = *(str + m + count);
count++;
}
*(str + m - flag + 1 + count) = '\0';
m = m - flag ;
}
flag = 0;
m++;
}
}
Este algoritmo tiene un problema en leetcode, que es que expirará el tiempo de espera. Como puede ver en lo anterior, no hay lugar para la optimización en el método de invertir cadenas. El tiempo de espera debe deberse al método de eliminación de espacios. La implementación del método de eliminar espacios es que si se encuentran espacios adicionales, la cadena después de los espacios avanzará. En el peor de los casos, el número de movimientos de personajes debe ser aproximadamente: el segundo personaje se mueve una vez, el tercer personaje se mueve dos veces y el enésimo personaje se mueve n-1 veces, la complejidad del tiempo es O (n<sup>2</sup>). De hecho, no es necesario moverse tantas veces. Solo es necesario mover un personaje una vez. El método mejorado para eliminar espacios es el siguiente:
void RemoveEmptyChar1(char* str) {
char * i = str;
char * j = str;
while (*i && (*i == ' ')) {
if (i == str) {
j = i;
while (*j && (*j == ' ')) {
j++;
}
if (!*j) {//说明全是空格
i = j;
}
while (*j && (*j != ' ')) {
*i = *j;
*j = ' ';
i++;
j++;
}
}
else{
if (*(i+1) == ' ') {
j = i+ 1;
while (*j && (*j == ' ')) {
j++;
}
i++;
while (*j && (*j != ' ')) {
*i = *j;
*j = ' ';
i++;
j++;
}
}
else{
i++;
}
}
}
//先去掉尾部的空格
int m = strlen(str) -1;
while (*(str + m) == ' ') {
*(str + m) = '\0';
m--;
}
}
Después de la mejora, el tiempo de ejecución de leetcode es de 4 ms y la mejor respuesta enviada en leetcode es de 0 ms. Eché un vistazo y descubrí que el método para voltear la cuerda es el mismo que el mío. La diferencia es el método de eliminar espacios. El método para eliminar espacios en 0 ms es el siguiente:
void updateString(char *s) {
int i = 0;
int end = 0;
int index = 0;
bool flag = false;
while (s[i] == ' ') {
i++;
}
while (s[i] != '\0') {
if (s[i] == ' ') {
flag = true;
} else {
if (flag) {
index = end + 1;
end = index + 1;
flag = false;
} else {
index = end;
end++;
}
if (i > index) {
s[index] = s[i];
s[i] = ' ';
}
}
i++;
}
s[end] = '\0';
}
Se puede ver que no hay anidamiento de bucles en su implementación, lo que significa que solo usó un bucle para hacerlo. Cuando lo implementó, movió como máximo un personaje a la vez. En cuanto a mi implementación anterior, en un bucle, si es necesario moverlo, se moverá al menos una palabra, todo con bucles anidados.
Revisión
El siguiente artículo proviene de: https://littlebitesofcocoa.com/251-face-aware-image-views-with-aspectfillfaceaware;. Habla sobre el uso despectfillfaceaware para darse cuenta de que al configurar una imagen para imageView, si la imagen contiene una cara, la cara se puede mostrar automáticamente en el centro.
Vistas de imágenes con reconocimiento de rostros con AspectFillFaceAware (use AspectFillFaceAware para permitir que imageView reconozca rostros)
Cuando usamos UIImageViews, a veces los modos de contenido integrados pueden obstaculizar nuestro estilo.
Cuando usamos UIImageViews, a veces el modo de contenido integrado destruye nuestro estilo y no puede satisfacer nuestras necesidades.
Muchas veces, mostramos fotografías de personas. En estos casos, sería fantástico si de alguna manera se pudiera indicar a la vista de imagen que recorte inteligentemente la foto alrededor del rostro de la persona.
Muchas veces mostramos fotografías de personas. En estos casos, sería fantástico si la vista de imagen pudiera de alguna manera recortar inteligentemente la foto alrededor del rostro de la persona.
Hoy revisaremos una biblioteca de Beau Nouvelle llamada AspectFillFaceAware. Es súper simple, echemos un vistazo.
Hoy veremos una biblioteca de clases de Beau Nouvelle llamada AspectFillFaceAware. Es muy sencillo, echemos un vistazo.
AspectFillFaceAware es esencialmente solo una extensión de UIImageView. Proporciona dos formas de configurar una vista de imagen para que sea “consciente de la cara”.
AspectFillFaceAware es esencialmente solo una extensión de UIImageView. Proporciona dos métodos para configurar la vista de imágenes para “reconocimiento facial”.
El primero está en Interface Builder, podemos habilitar la función activándola en el Inspector. (¿No ve la opción? Ejecute su proyecto una vez, luego debería aparecer).
La primera forma es en Interface Builder, podemos habilitar la función hojeando Funciones en el Inspector. (¿No ves la opción? Ejecuta tu proyecto una vez y debería aparecer).
<img src=“/img/15334638167496.jpg” ancho=“50%” alto=“50%” /> Así es como se ve:

También podemos habilitar la funcionalidad en el código configurando la imagen de la vista de imagen usando esta nueva función:
También podemos utilizar esta nueva característica a través del código:
imageView.set (imagen: avatar, focusOnFaces: verdadero) Incluso podemos lanzar un radio de esquina rápido en la capa de la vista de imagen para probar la funcionalidad “consciente de la cara” en una vista circular. (es decir, avatares de usuario):
Incluso podemos realizar un radio de esquina rápido en la capa de la vista de imagen para probar la función de “reconocimiento facial” en la vista circular. (es decir, avatar de usuario):
let radio = imageView.bounds.size.width / 2.0 imageView.layer.cornerRadius = radio
Debajo del capó, la biblioteca utiliza un CIDetector de baja precisión con un tipo de CIDetectorTypeFace para manejar la detección de rostros real. ¿Quieres profundizar más aquí? Cubrimos los CIDetectors en el Bite #87.
Debajo del capó, la biblioteca utiliza un CIDetector de baja precisión con el tipo CIDetectorTypeFace para manejar la detección de rostros real. ¿Quieres profundizar más? Presentamos el enfoque CIDetectors en el Bite #87.
Consejo
####1 ¿Cómo establecer puntos de interrupción para los métodos del sistema cuando se usa Xcode para depurar? La respuesta es el punto de ruptura. Por ejemplo, para establecer el punto de interrupción del métodoContentInset, puede utilizar el siguiente comando:
breakpoint set -S setContentInset:
Para más detalles, consulte: https://www.jianshu.com/p/8e9fc9a8ab78?from=jiantop.com
####2 Optimización de UITableView Se puede decir que la optimización de UITableView es un tema que nunca pasará de moda en el desarrollo de iOS. Aquí hay un resumen de ideas de optimización. Puede buscar en Google los métodos específicos usted mismo. La idea general es la siguiente:
-
Reducir la cantidad de cálculos de CPU/GPU 1.1 Mecanismo de reutilización de células 1.2 Almacenar en caché la altura de la celda y el marco de los controles en la celda del modelo 1.3 Reducir el nivel de controles dentro de la celda 1.4 Logre el efecto de esquina redondeada del avatar cubriendo la imagen de esquina redondeada
-
Células de carga bajo demanda 2.1 Cargue solo celdas visibles en el método cellForRow: 2.2 Supervise el desplazamiento rápido de la vista de tabla y guarde los índices de las tres filas antes y después del rango de desplazamiento objetivo
-
Procesamiento asincrónico de células. 3.1 Carga asincrónica de imágenes de red 3.2 Dibujar imágenes locales de forma asincrónica 3.3 Dibujo asincrónico de UIView 3.4 Dibujo asincrónico de NSString 3.5 Dibujo asincrónico de UILabel
Compartir
Compartiendo una pregunta hoy, vi esta pregunta en un grupo hoy
<img src=“/img/20180809225650469.png” ancho=“50%” alto=“50%” />
¿Cuál elegirás? Elija D?
Según mis conocimientos previos, debería elegir D, pero cuando vi que alguien decía que eligiera B, lo intenté. El código de prueba es el siguiente:
- (void)viewDidLoad {
[super viewDidLoad];
for (int i =0; i < MAXFLOAT; i++) {
@autoreleasepool{
UIImage *img = [[UIView alloc] init];// A
UILabel *lab = [[UILabel alloc] init];// B
NSString *str = @"abc";
str = [str stringByAppendingString:@"xyz"];// C
}
}
}
El resultado es realmente B. B hará que la memoria siga aumentando. Después de las pruebas, se descubrió que, independientemente del grupo de liberación automática, B hará que la memoria siga aumentando. Los otros dos no harán que la memoria siga aumentando. Es extraño. Es lógico que después de agregar @autoreleasepool, la memoria se libere automáticamente cuando alcance un cierto valor. La explicación en el grupo es:
- Relacionado con hilos
- Apple ha optimizado el bucle for. Si no es UIView y sus subclases, se procesará en un subproceso.
- El objeto UIView se creará automáticamente en el hilo principal.
- Si coloca UIImage en el hilo principal para su procesamiento, la memoria aún aumentará.
- El método de liberación del grupo de liberación automática del subproceso principal es diferente del del subproceso secundario.
Pero todavía no entiendo por qué: 1 lab es una variable local, excepto que se debe liberar el corchete derecho del bucle for. 2 Se agregó @autoreleasepool, que debería liberarse cuando la memoria alcance su punto máximo. ? ? ?
What to read next
Want more posts about ARTS?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home