[LeetCode] -una pregunta relativamente única-2

prefacio

Grabación de algunas de las preguntas más singulares que LeetCode encontró al resolver preguntas, Parte 2

134. Gasolinera

Supongamos que comenzamos desde la estación de servicio con el subíndice inicio y actualmente estamos en la estación de servicio con el subíndice i. Cada vez que queremos ir a la siguiente estación de servicio, primero restamos el costo [i] para determinar si el volumen de petróleo actual es menor que 0. Si es menor que 0, significa que no puede comenzar desde el principio, de lo contrario, puede continuar hasta la siguiente gasolinera. Si finalmente puedes ir a i y comenzar son iguales, significa que puedes caminar durante una semana comenzando desde el inicio y regresando al inicio.

Si en el momento i, petróleo = petróleo - costo[i] y se encuentra que el petróleo es menor que 0 en ese momento, entonces no podemos comenzar desde el principio y debemos elegir el siguiente punto de partida. Entonces, ¿dónde debemos elegir el siguiente punto de partida? ¿punto?

¿Seleccionar al inicio + 1? Definitivamente es posible. Este es el método de bucles de dos niveles. Enumere cada subíndice i e intente ver si puede recorrer un círculo comenzando desde i. Si no, simplemente enumere i + 1 hasta que se enumere una i con una solución. y devuelve i. O si no hay solución después de enumerar n números, se devolverá -1.

Pero este no es el mejor enfoque. Supongamos que comienza desde el inicio y llega a un determinado subíndice tmp, desea continuar hacia abajo y descubre que oil = oil - cost[i] es menor que 0, es decir, no puede ir a tmp + 1, luego cambie comenzar a comenzar + 1 es inútil, porque como puedes ir de principio a comienzo + 1, significa que cuando vas a comenzar + 1, hay exceso de aceite o simplemente aceite agotado, y si comienzas directamente desde inicio + 1 , Es simplemente equivalente a quedarse sin aceite al caminar de principio a fin + 1. Es decir, la contribución desde el principio al seguimiento es definitivamente mejor o igual que comenzar desde el principio + 1, por lo que no hay Necesito comenzar desde comenzar + 1 comenzar a caminar

Por lo tanto, cuando inicialmente elegimos comenzar en la posición start y nos quedamos sin combustible cuando llegamos a j, entonces el siguiente punto de partida no puede ser [begin,j], ni puede ser [0,begin], lo que significa que si j = = n - 1, o j llega al lado izquierdo de inicio y j < inicio, entonces no hay ningún punto de inicio que pueda cumplir las condiciones para elegir, y se devuelve -1 directamente.

public int canCompleteCircuit(int[] gas, int[] cost) {
    
    
    int n = gas.length;
    int begin = 0;
    int i = 0;
    int oil = gas[begin];
    while(true){
    
    
        oil = oil - cost[i];
        if(oil < 0){
    
    
            if(i < begin || i == n - 1) return -1;
            begin = i == n - 1 ? 0 : i + 1;
            i = begin;
            oil = gas[begin];
        }else{
    
    
            i = i == n - 1 ? 0 : i + 1;
            if(i == begin) return begin;
            oil += gas[i];
        }
    }
}

1352. El producto de los últimos K números.

Utilice la variable len para registrar el número de números en la lista actual. Pre [i] en la matriz pre representa el producto de los primeros i números en la lista, y pre [0] se establece en 1.

Restablezca las matrices len y pre al agregar 0 a la lista. De esta manera, al obtenerProduct, si k es mayor que len, significa que los últimos k números de la lista deben contener al menos un 0, entonces el producto de los k números obtenidos debe ser 0 y se devuelve 0 directamente; en caso contrario , el producto de los últimos k números es igual a lo siguiente El producto de len números se divide por el producto de len - k números antes de k números entre len números, es decir, pre[len] / pre[len - k]

class ProductOfNumbers {
    
    
    int len;
    int[] pre;
    public ProductOfNumbers() {
    
    
        pre = new int[40001];
        pre[0] = 1;
        len = 0;
    }
    public void add(int num) {
    
    
        if (num == 0) len = 0;
        else{
    
    
            pre[++len] = num * pre[len - 1];
        }
    }
    
    public int getProduct(int k) {
    
    
        if (len < k) return 0;
        return pre[len] / pre[len - k];
    }
}

31. Siguiente permutación

Consulte la solución y vea los comentarios del código para obtener un resumen personal.

public void nextPermutation(int[] nums) {
    
    
    int len = nums.length;
    if(len == 1) return;
    int index = len - 1;
    while(index > 0){
    
    
    	//1. 从后往前找第一对严格升序的元素对,即nums[index - 1] < nums[index]
        if(nums[index - 1] < nums[index]){
    
    
            int last = len - 1;
            //2. 在[index,len)中从后往前找第一个大于nums[index - 1]的元素
            while(last >= index){
    
    
            	//3. 交换这个元素跟nums[index - 1]
                if(nums[last] > nums[index - 1]){
    
    
                    nums[last] ^= nums[index - 1];
                    nums[index - 1] ^= nums[last];
                    nums[last] ^= nums[index - 1];
                    break;
                }
                last--;
            }
            //4. 把index开始往后的区间排序
            Arrays.sort(nums,index,len);
            return;
        }
        index--;
    }
    //5. 找不到符合要求的升序元素对,说明整个数组为降序排序,也就是对应最大的排列,
    //那么下一个排列就是最小的排列,也就是整个数组升序排序
    Arrays.sort(nums);
}

556. El siguiente gran elemento III

Se puede encontrar que el propósito de esta pregunta es el mismo que el de la pregunta 31 anterior. La siguiente disposición es la misma, por lo que puede usar el mismo método para completar esta pregunta, pero si convierte el número en una matriz, requiere una complejidad espacial de O(k), k el número de dígitos para n

En la solución oficial se utiliza otro método de complejidad espacial O (1) . La idea es la misma que la siguiente disposición en 31., pero la operación se realiza directamente en n. Después de digerirlo yo mismo, copié el código y la idea general sigue siendo la misma que la de la pregunta 31. Para ser coherente con la pregunta 31, n corresponde al subíndice de pequeño a grande y de mayor a menor:

  1. Encuentre el primer par ascendente de atrás hacia adelante, es decir, encuentre el índice de subíndice tal que el número en el índice - 1 sea menor que el número en el índice: tmp % 10 es el dígito más bajo, tmp / 10 % 10 es el segundo último dígito más bajo, divida tmp entre 10 cada vez hasta que tmp % 10 > tmp / 10 % 10. En este momento, tmp % 10 es el número en el índice, tmp / 10 % 10 es el número en el índice - 1, y luego divida tmp por 10, el bit más bajo es índice - 1 bit
  2. Después del índice (incluido el índice), busque el primer número mayor que el número en el índice - 1 (tmp % 10) de atrás hacia adelante: Sea tmp2 = n y juzgue si tmp2 % 10 es mayor que tmp % 10 cada vez, sí. En este caso, el bit más bajo de tmp2 es el primer número de atrás hacia adelante que es mayor que el número en el índice - 1. Luego intercambie el bit más bajo de tmp2 con el bit más bajo de tmp
  3. Finalmente, ordene los números posteriores comenzando desde el índice en orden ascendente. Dado que el índice - 1 y el número en el índice son el primer par ascendente encontrado por n de atrás hacia adelante, los números después del índice están todos en orden descendente. Puede ordenarlos en orden ascendente volteándolos directamente.
public int nextGreaterElement(int n) {
    
    
    int tmp = n,count = 1; //count表示index-1(不包括index-1)后的位数
    for(;tmp >= 10 && tmp % 10 <= tmp / 10 % 10;tmp /= 10){
    
    
        count++;
    }
    tmp /= 10; //此时tmp为n除去index(包括index)后的位剩余的部分,即最低位为index-1
    if(tmp == 0) return -1;
    //tmp%10即为index-1;count表示从后往前第一个大于index-1的数的右边有多少位数(不包括这个数本身)
    int tmp2 = n,indexMinusOne = tmp % 10,count2 = 0; 
    while(tmp2 > 0 && tmp2 % 10 <= indexMinusOne){
    
    
        tmp2 /= 10;
        count2++;
    }
    //此时tmp2%10即为从后往前第一个大于index-1的数,将其与index-1上的数交换
    tmp += tmp2 % 10 - indexMinusOne;
    tmp2 += indexMinusOne - tmp2 % 10;
    count -= count2;
    //要反转index后的数,共count个数
    //后count2个数在n中,所以这里先反转后count2个数
    while(count2 > 0){
    
    
        tmp = tmp * 10 + n % 10;
        n /= 10;
        count2--;
    }
    //再将剩下的count - count2个数反转,这几个数在tmp2中而不是n,
    //因为从后往前第一个大于index - 1上的数的数已经改变了,而n自始至终未改变过
    while(count-- > 0){
    
    
        int originTmp = tmp;
        tmp = tmp * 10 + tmp2 % 10;
        //记录运算前的tmp值,计算后根据结果是否一致判断是否溢出
        if(tmp / 10 != originTmp) return -1; 
        tmp2 /= 10;
    }
    return tmp;
}

169. La mayoría de los elementos

El método proviene de la solución oficial. El algoritmo se llama algoritmo de votación de Boyer-Moore.

Supongamos que estamos realizando una encuesta y cada elemento de la matriz es un candidato. Durante el proceso de votación, cada elemento será enumerado para permitirles votar. La persona que actualmente tiene más votos se considera candidato y se registra como candidato. Inicialmente podemos establecer un número aleatorio, lo que no afecta el resultado final, el número actual de votos se registra como voto.

Luego, cuando le toca votar a un elemento, su estrategia de votación es: antes de la votación formal, si el número de votos recibidos por el candidato actual es 0, entonces el elemento puede elegirse a sí mismo como nuevo candidato. A continuación, vote formalmente. Si el candidato es usted mismo, agregue uno al número de votos; de lo contrario, reste uno del número de votos. El
candidato final es la moda en la matriz, que naturalmente es el elemento mayoritario requerido para esta pregunta. .

Se puede entender de esta manera: según las reglas de votación, todos tenderán a votar positivamente por sí mismos (+1) y votos negativos por los demás (-1), por lo que, dado que el elemento mayoritario representa una proporción mayor, el número de votos Naturalmente, el que obtenga debería ser el mayor; de manera similar, para otros números no modales, dado que hay más elementos que son diferentes a él, más personas le darán votos negativos, por lo que el número de votos que obtenga debería tender a ser negativo. .

public int majorityElement(int[] nums) {
    
    
    int len = nums.length;
    int candidate = -1,vote = 0;
    for(int i : nums){
    
    
        if(vote == 0){
    
    
            candidate = i;
        }
        vote += i == candidate ? 1 : -1;
    }
    return candidate;
}

La espada apunta a la Oferta 45. Organice la matriz en el número más pequeño

Defina las siguientes reglas de clasificación : para nums[i] y nums[i + 1], compare el número representado por la cadena compuesta por nums[i] add nums[i + 1] con nums[i + 1] add nums[i ] ¿Qué número representado por la cadena obtenida es mayor? Si el primero es mayor, entonces nums[i] tiene prioridad sobre nums[i + 1]; de lo contrario, nums[i + 1] tiene prioridad sobre nums[i]

Ordene la matriz en orden ascendente de acuerdo con esta clasificación y luego agregue cada elemento en orden, el resultado es el número más pequeño.

class Solution {
    
    
    public String minNumber(int[] nums) {
    
    
        if(nums == null || nums.length == 0) return "";
        //先转化为字符串数组。如果还是使用整形数组的话,后续在排序比较的时候还是需要将整形数据转化为字符串进行append
        //尝试之后发现先转化为字符串的话耗时会更少
        String[] s = new String[nums.length];
        for(int i = 0;i < nums.length;i++){
    
    
            s[i] = String.valueOf(nums[i]);
        }
        //使用快排进行排序。也可以直接使用 Arrays.sort() 进行排序
        quickSort(s,0,s.length - 1);
        //使用 StringBuilder 把排序后的所有字符串append起来得到答案
        StringBuilder res = new StringBuilder();
        for(String str : s){
    
    
            res.append(str);
        }
        return res.toString();
    }
    public void quickSort(String[] s,int l,int r){
    
    
        if(l >= r){
    
    
            return;
        }
        /* 枢轴随机化的操作
        int pivotIndex = new Random().nextInt(r - l + 1) + l;
        if(pivotIndex != l && s[pivotIndex] != s[l]){
            swap(s,l,pivotIndex);
        }*/
        String pivot = s[l];
        int left = l,right = r;
        while(left < right){
    
    
        	//(pivot + s[right]).compareTo(s[right] + pivot) < 0,则pivot优先级低于right
            while(left < right && (pivot + s[right]).compareTo(s[right] + pivot) < 0) right--;
            while(left < right && (pivot + s[left]).compareTo(s[left] + pivot) >= 0) left++; 
            if(left < right){
    
    
                swap(s,left,right);
            }
        }
        s[l] = s[left];
        s[left] = pivot;
        quickSort(s,l,left - 1);
        quickSort(s,left + 1,r);
    }
    public void swap(String[] s,int l,int r){
    
    
        String tmp = s[l];
        s[l] = s[r];
        s[r] = tmp;
    }
}

179. Número máximo

Esta pregunta se refiere a la Oferta 45. Organizar la matriz en el número más pequeño es todo lo contrario. La idea es la misma. Al ordenar, simplemente cámbielo a orden de prioridad descendente.

public String largestNumber(int[] nums) {
    
    
    String[] str = new String[nums.length];
    for(int i = 0;i < nums.length;i++){
    
    
        str[i] = String.valueOf(nums[i]);
    }
    Arrays.sort(str,(a,b)->{
    
    
    	//条件成立说明a优先于b,那么按照降序排序应该返回-1否则返回1
        return (a + b).compareTo(b + a) > 0 ? -1 : 1;
    });
    StringBuilder sb = new StringBuilder();
    for(String s : str){
    
    
        sb.append(s);
    }
    int len = sb.length();
    int i = 0;
    //去除前导0
    while(i < len && sb.charAt(i) == '0'){
    
    
        i++;
    }
    String res = sb.substring(i);
    //res为去除前导0后的字符串,有可能原字符串都为0,那么去完之后就都剩空串了,此时应该返回0而不能直接返回空串
    return "".equals(res) ? "0" : res;
}

Supongo que te gusta

Origin blog.csdn.net/Pacifica_/article/details/126473890
Recomendado
Clasificación