[LeetCode] -Classificar

Prefácio

Perguntas relacionadas à classificação de registros encontradas ao escrever perguntas no LeetCode

Pergunta da entrevista 10.01. Mesclar matrizes classificadas


Mesclagem bidirecional, crie temporariamente uma matriz de comprimento m + n, em seguida, execute uma mesclagem bidirecional e classifique os elementos nas matrizes A e B em ordem crescente e armazene-os na matriz temporária e, finalmente, copie os elementos do array temporário para A. Um array temporário é necessário, e a complexidade do espaço é O (m + n), porque se for mesclado diretamente no array A, quando um elemento no array em B for maior que um elemento em A, os elementos em A serão substituídos. Observe que
A O tamanho inicial da matriz é m + n. Esta configuração definitivamente não é arbitrária. Para mesclar os elementos dos dois arrays e armazená-los diretamente no array A, você pode percorrer os arrays A e B na ordem inversa e mesclar os elementos do maior para o menor. Veja o código para detalhes.

public void merge(int[] A, int m, int[] B, int n) {
    
    
	//从A数组的最后面往前归并元素
    int index = m + n - 1;
    int pa = m - 1;
    int pb = n - 1;
    while(pa >= 0 && pb >= 0){
    
    
        if(A[pa] > B[pb]){
    
    
            A[index--] = A[pa--];
        }else{
    
    
            A[index--] = B[pb--];
        }
    }
    while(pa >= 0){
    
    
        A[index--] = A[pa--];
    }
    while(pb >= 0){
    
    
        A[index--] = B[pb--];
    }
}

Fila rápida para resolver os K principais problemas

Quando encontrei o problema Top K antes, minha primeira reação foi usar a fila de prioridade . Quanto mais perguntas fiz depois, descobri que muitas das soluções usavam fila rápida para resolver esses problemas, e o consumo de tempo era muito menor do que a fila prioritária.

Pergunta da entrevista 17.14. Número mínimo de K

Ao ver o k mínimo, a primeira coisa que vem à mente é usar a fila/heap de prioridade para resolver o problema; além disso, você também pode classificar o array primeiro e depois pegar diretamente os k números principais. No entanto, ambos os métodos requerem ajuste de toda a matriz, mas precisamos apenas dos menores k números; e os menores k números retirados por esses dois métodos estão todos em ordem, mas a questão não requer ordem. Em suma, estas duas abordagens causarão operações redundantes

Você pode usar a ideia de classificação rápida: a operação de classificação rápida consiste em colocar um número (pivô) na posição onde ele deve ser armazenado em ordem, garantindo que todos os números à esquerda sejam menores ou iguais a ele, e todos os números à direita são maiores que iguais a ele e não garantem a ordem dos números nos lados esquerdo e direito. Portanto, supondo que, uma vez concluída a operação, o pivô seja colocado onde deveria estar e seja descoberto que é exatamente a posição do subscrito k, então os menores k números em toda a matriz são exatamente os k números elevados ao à esquerda dele (ou seja, abaixo dos números rotulados [0,k - 1])

Então, apenas com base na classificação rápida, cada vez que um pivô é organizado para determinar sua posição, se for a posição do índice k, retorne os k números para a esquerda; se for a posição do índice k - 1, retorne o outro O número k - 1 à esquerda mais ele mesmo; se for maior que k, execute uma classificação rápida na parte esquerda; se for menor que k - 1, execute uma classificação rápida na parte direita

class Solution {
    
    
    int[] quickSort(int[] arr,int l,int r,int k){
    
    
        if(l >= r) return null;
        int ll = l;
        int rr = r;
        while(rr > ll){
    
    
        	//这里要用">=",因为有相等的数并不影响索引k的位置的左边是最小k个数
            while(arr[rr] >= arr[l] && rr > ll) rr--;
            while(arr[ll] <= arr[l] && rr > ll) ll++;
            if(rr != ll){
    
     //这里如果改成了rr > ll,用时就变 2ms 了
                swap(arr,rr,ll);
            }
        }
        swap(arr,rr,l);
        if(rr == k) return Arrays.copyOfRange(arr,0,rr);
        if(rr == k - 1) return Arrays.copyOfRange(arr,0,rr + 1);
        if(rr > k) return quickSort(arr,l,rr - 1,k);
        if(rr < k) return quickSort(arr,rr + 1,r,k);
        return null;
    }
    public int[] smallestK(int[] arr, int k) {
    
    
        if(k == 0) return new int[0];
        return quickSort(arr,0,arr.length - 1,k);
    }
    void swap(int[] arr,int i,int j){
    
    
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

215. O K-ésimo maior elemento em uma matriz

Copiei a maior parte do código desta questão do código de número K mínimo acima.

A ideia é muito simples. O K-ésimo maior elemento na matriz é na verdade o elemento cujo subscrito é nums.length - k após a classificação. Portanto, use a classificação rápida para processar a matriz e encontrar o elemento cujo subscrito é nums.length - após a classificação .k elementos podem ser

Deve-se notar que nesta questão, se o pivô é selecionado aleatoriamente tem um grande impacto no tempo de execução - se o número mais à esquerda na seleção for o pivô, o tempo de resultado é de cerca de 12ms; enquanto o pivô é aleatório Após a conversão, o resultado leva 1ms. Em suma, a randomização pivot é geralmente necessária

class Solution {
    
    
    int quickSort(int[] arr,int l,int r,int k){
    
    
        if(l == r) return arr[l]; //注意这里l == r,即剩下一个数时直接返回
        //===========枢轴随机选取================//
        int randomIndex = new Random().nextInt(r + 1 - l) + l;
        swap(arr,l,randomIndex);
        //=====================================//
        int ll = l;
        int rr = r;
        while(rr > ll){
    
    
            while(arr[rr] >= arr[l] && rr > ll) rr--;
            while(arr[ll] <= arr[l] && rr > ll) ll++;
            if(rr != ll){
    
     
                swap(arr,rr,ll);
            }
        }
        swap(arr,rr,l);
        if(rr == k) return arr[rr];
        if(rr > k) return quickSort(arr,l,rr - 1,k);
        if(rr < k) return quickSort(arr,rr + 1,r,k);
        return -1;
    }
    void swap(int[] arr,int i,int j){
    
    
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public int findKthLargest(int[] nums, int k) {
    
    
        return quickSort(nums,0,nums.length - 1,nums.length - k);
    }
}

347. Principais K elementos de alta frequência

A ideia de classificação de baldes. Conte o número de ocorrências de cada número na matriz e, em seguida, pegue o número correspondente do maior para o menor de acordo com o número de ocorrências. Se você pegar k números suficientes, obterá a resposta.

public int[] topKFrequent(int[] nums, int k) {
    
    
    List<Integer> res = new ArrayList();
    //使用一个map记录所有元素的出现次数,键为某个元素,值为其出现次数
    HashMap<Integer,Integer> map = new HashMap();
    for(int num : nums){
    
    
        map.put(num,map.getOrDefault(num,0) + 1);
    }
    //再以出现次数为数组下标,出现次数相同的元素构成的列表作为数组元素
    List<Integer>[] list = new List[nums.length + 1];
    for(int key : map.keySet()){
    
    
        int i = map.get(key);
        if(list[i] == null){
    
    
           list[i] = new ArrayList();
        } 
        list[i].add(key);
    }
    //这样,数组中下标从大到小的元素就是出现频率从高到低的元素,所以按照下标从大到小取够k个数就是出现频率最高的k个数
    for(int i = list.length - 1;i >= 0 && res.size() < k;i--){
    
    
        if(list[i] == null) continue;
        res.addAll(list[i]);
    }
    //由于是使用ArrayList收集元素,要转化为数组
    int size = res.size();
    int[] ans = new int[size];
    for(int i = 0;i < size;i++){
    
    
        ans[i] = res.get(i);
    }
    return ans;
}

Espada refere-se à oferta 51. Pares invertidos em uma matriz

Sem olhar para a solução, eu não teria pensado que a classificação por mesclagem poderia ser usada para resolver esse problema. A classificação por mesclagem é dividida em três etapas: particionamento, classificação e mesclagem. Se atualmente quisermos mesclar os dois intervalos classificados [a j,…,bi+2,bi+1] e [bi,…,a2,a1 1 , p2 aponta para b i+1 e, em seguida, compara repetidamente o número apontado pelos dois ponteiros que é menor, coloca-o na matriz classificada e, em seguida, move o ponteiro para trás. Então, como integrar a operação de encontrar o reverso -order pares neste processo? Se julgarmos que o número apontado por p1 é maior que o número apontado por p2, uma vez que o intervalo a está organizado em ordem crescente, os números subsequentes de p1 também serão maiores que p2. Ou seja, p1 e os subsequentes números de p1 formam um par de ordem inversa com p2. Calcule quantos números totais são adicionados a res. Além disso, p2 aumentará em um neste momento e não será utilizado para cálculos subsequentes, garantindo que a contribuição de cada par de números para o logaritmo na ordem inversa será calculada apenas uma vez.

class Solution {
    
    
    public int[] tmp;
    public int res = 0;
    public int reversePairs(int[] nums) {
    
    
        tmp = new int[nums.length];
        mergeSort(nums,0,nums.length - 1);
        return res;
    }
    public void mergeSort(int[] nums,int l,int r){
    
    
        if(l >= r) return;
        int mid = (l + r) >> 1;
        mergeSort(nums,l,mid);
        mergeSort(nums,mid + 1,r);
        merge(nums,l,mid,r);
    }
    public void merge(int[] nums,int l,int mid,int r){
    
    
        System.arraycopy(nums,l,tmp,l,r - l + 1);
        int index = l;
        int p1 = l,p2 = mid + 1;
        while(p1 <= mid && p2 <= r){
    
    
            if(tmp[p1] > tmp[p2]){
    
    
                res += mid - p1 + 1; //相比于单纯的归并排序,其实只加了这一行代码
                nums[index++] = tmp[p2++];
            }else{
    
    
                nums[index++] = tmp[p1++];
            }
        }
        while(p1 <= mid){
    
    
            nums[index++] = tmp[p1++];
        }
        while(p2 <= r){
    
    
            nums[index++] = tmp[p2++];
        }
    }
}

Acho que você gosta

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