Classificação Radix e uso de arrays para simplificar a resolução de problemas

Hongdou é insuportável de olhar, seus olhos estão cheios de lágrimas de saudade

Insira a descrição da imagem aqui

 Este artigo tem como objetivo principal ajudá-lo a se tornar proficiente no uso de matrizes para fazer julgamentos. Depois de ler este artigo, você poderá usar essa ideia em questões futuras. É claro que usar esse método para as questões do exemplo pode não ser a solução ideal, mas é definitivamente Você pode ver como pode resolver o problema sem pensar muito. Claro, também apresentarei outros métodos dos problemas listados para que todos possam pensar. Sem mais delongas, vamos direto ao ponto.

Radix sort
Ideia: um array foi fornecido e o array é a sequência que precisamos classificar. Em seguida, abra um array e o número n do array é o número a ser classificado. O maior número é +1 e todos são inicializados em 0. Classifique os números na matriz conforme necessário, encontre a posição subscrita do número na matriz recém-aberta e ++ o número nessa posição.
Por exemplo:
Insira a descrição da imagem aqui
 A lógica é muito simples e falamos diretamente sobre como otimizar. Pode-se ver à primeira vista que esse tipo de arranjo de pensamento também deixa muito espaço em alguns casos, como se os números ordenados estiverem todos entre 1.000 e 2.000 e começarmos a abrir o espaço a partir de 0, os primeiros 1.000 espaços serão usados ​​em vão, resultando em um enorme desperdício de espaço.
Podemos primeiro percorrer e encontrar o valor máximo e o valor mínimo no array a ser classificado. A diferença entre os dois mais 1 é o espaço que precisamos abrir.
O código é o seguinte

//基数排序
void CountSort(int* a, int n)
{
    
    
	int min = a[0], max = a[0];
	for (int i = 0; i < n; i++)
	{
    
    
		if (a[i] < min)
		{
    
    
			min = a[i];
		}
		if (a[i] > max)
		{
    
    
			max = a[i];
		}
	}
	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
    
    
		perror("malloc fail");
		return;
	}
	memset(count, 0, sizeof(int) * range);
	//统计数据出现的次数
	for (int i = 0; i < n; i++)
	{
    
    
		count[a[i] - min]++;//开的空间是减去min的,所以排序数组中的数在存储时也要减去min。
	}
	int j = 0;
	for (int i = 0; i < range; i++)
	{
    
    
		while (count[i]--)
		{
    
    
			a[j++] = i + min;//该位置的数出现几次,就统计出几次
		}
	}
}

Resumo da classificação Radix

  1. A classificação por contagem é muito eficiente quando o intervalo de dados é concentrado, mas seu escopo e cenários aplicáveis ​​são limitados. E se for um decimal? Você não pode armazenar usando subscritos.
  2. Complexidade de tempo: O(N(intervalo))
  3. Complexidade do espaço: O(N)

OK, apresente cinco perguntas que usam essa ideia para ajudar todos a dominar esse método de fazer perguntas
1, Coleta de erros
Insira a descrição da imagem aqui
Existem muitas soluções para este problema
 Ideia 1: A coisa mais fácil de pensar é classificar primeiro, e então você poderá encontrar facilmente os números que faltam, e nós já sabemos disso Contendo 1 a n, você pode somar e subtrair diretamente todos os elementos da matriz onde ocorreu o erro.Por exemplo, copie 5 em 7 e o resultado após a subtração será -2, então o número repetido será 5 mais 2 a 7.
 Ideia 2: Use diretamente a ideia de classificação radix. Reabra uma matriz (inicialize tudo para 0), sem classificar, adicione diretamente as posições subscritas correspondentes a todos os números no conjunto fornecido. Claro, se um determinado número não aparecer, então o número nesta posição no novo array aberto é 0, o repetido é 1.
O código é o seguinte

int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
    
    
    int *array1,*array2,i;
    array1=(int*)calloc(numsSize,sizeof(int));
    array2=(int*)malloc(sizeof(int)*2);
    for(i=0;i<numsSize;i++)
    {
    
    
        array1[nums[i]-1]+=1;
    }
    for(i=0;i<numsSize;i++)
    {
    
    
        if(array1[i]==2)
        array2[0]=i+1;
        else if(array1[i]==0)
        array2[1]=i+1;
    }
    *returnSize=2;
    return array2;    
}

 A lógica é clara, a complexidade do tempo é O(N) e a complexidade do espaço é O(N). Claro, você também pode adicionar um julgamento para sair do loop logo após encontrar dois números para reduzir o número de loops.


2,Contagem de caracteres
Insira a descrição da imagem aqui

 Da mesma forma, ainda precisamos descobrir se um determinado número existe em um intervalo ou o número de vezes que um determinado número aparece. Os caracteres também são inteiros. Você pode usar os números inteiros representados por caracteres. Ou ainda pode resolver o problema de acordo com a ideia acima. Você só precisa forçar a conversão., outras ideias são todas iguais.
O código é o seguinte

#include <stdio.h>
int main() {
    
    
    int i = 0;
    int count = 0;
    char arr1[500];
    int arr[127] = {
    
     0 };

    scanf("%s", arr1);
    while (arr1[i] != '\0')
    {
    
    
        arr[(int)arr1[i]] = 1;
        i++;
    }
    for (int j = 0; j < 127; j++)
    {
    
    
        if (arr[j] == 1)
        {
    
    
            count++;
        }
    }
    printf("%d", count);
    return 0;
}

 Da mesma forma, desde que essa ideia seja usada, a complexidade do tempo geralmente é O(N).Como diz a pergunta, o intervalo está entre 0 e 127. É muito legal usar essa ideia.


3,A maioria dos elementos
Insira a descrição da imagem aqui
 Dado um array, encontra o número de ocorrências no array maior que numsSize/2 Number, também podemos usar este método, mas este problema não pode ser resolvido usando este método, embora já saibamos quanto espaço queremos abrir (a complexidade do tempo é O(1) ), mas a diferença entre os valores máximo e mínimo no array é 2*10^9. Este número é muito grande, o que significa que o espaço que temos para abrir também é muito grande. Se quisermos resolver este problema , a complexidade do tempo é O(N) , é impossível executar usando este método. Mas você pode trapacear e ganhar pontos. Como mencionado acima, isso é apenas uma ideia. Claro, haverá outras soluções.
O código para usar subscritos de array é o seguinte

int majorityElement(int* nums, int numsSize) {
    
    
    int min = nums[0], max = nums[0];
	for (int i = 0; i < numsSize; i++)
	{
    
    
		if (nums[i] < min)
		{
    
    
			min = nums[i];
		}
		if (nums[i] > max)
		{
    
    
			max = nums[i];
		}
	}
    int range=max-min+1;
    int*arr=(int*)malloc(sizeof(int)*(range));
    for (int k = 0; k < range; k++)
	{
    
    
		arr[k] = 0;
	}
    for (int i = 0; i < numsSize; i++)
	{
    
    
		arr[nums[i] - min]++;
	}
	for(int j=0;j<range;j++)
    {
    
    
        if(arr[j]>numsSize/2)
        {
    
    
            return j+min;
        }
    }
	return -1;
}

 Se você olhar de perto, descobrirá que o método é muito semelhante ao método de classificação de raiz anterior, exceto que as coisas a serem julgadas ou obtidas após a conclusão do armazenamento são diferentes.
Se você executar esse código, ele não será aprovado porque alguns casos de uso são direcionados especificamente a ele.
Insira a descrição da imagem aqui
Pode-se descobrir que a maioria dos casos de uso foram aprovados
Insira a descrição da imagem aqui
 As estimativas restantes contêm esses dois números. Não sei se a otimização pode ser bem-sucedida , e não quero gastar tanto tempo. , se a diferença numérica na matriz no caso de uso não for tão grande, então a complexidade de tempo desta solução é O(N) e a complexidade do espaço é O(1 ).

OK, não podemos simplesmente colocar um método intransponível aqui.

Fale sobre o método de votação (muito inteligente)
 Aproveite o fato de que o número de vezes da maioria dos elementos no array é definitivamente maior que numsSIze/2, então use diferentes elementos para eliminar os mesmos objetos. Então, de baixo para cima, são definitivamente os mesmos elementos, ou seja, a maioria dos elementos que procuramos.
Insira a descrição da imagem aqui
O código é o seguinte

int majorityElement(int*nums,int numsSize)
{
    
    
    int candidate=nums[0];
    int flag=1;
    for(int i=1;i<numsSize;i++)
    {
    
    
        if(nums[i]==candidate)
        {
    
    
            flag++;
        }
        else
        {
    
    
            flag--;
            if(flag<0)
            {
    
    
                candidate=nums[i];
                flag=1;
            }
        }
    }
    return candidate;
}

4,Encontre todos os dados ausentes na matriz
Insira a descrição da imagem aqui

 Da mesma forma, esta questão também está relacionada ase um determinado número existe na matriz ou quantas vezes um determinado número aparece, usando o mesmo A ideia pode ser encontrada sem classificação, e a complexidade do tempo é O(N), mas abrimos espaço adicional. Quanto ao método de escrita avançado, vamos deixá-lo de lado primeiro.
O código é o seguinte

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize){
    
    
    int k=0;
    int*arr=(int*)malloc(sizeof(int)*(numsSize));
    int*ret=(int*)malloc(sizeof(int)*(numsSize));
    //memset(arr,0,(sizeof(int)*(numsSize+1)));
    for(int l=0;l<numsSize;l++)
    {
    
    
        arr[l]=0;
    }
    for(int i=0;i<numsSize;i++)
    {
    
    
        arr[nums[i]-1]++;
    }
    for(int j=0;j<numsSize;j++)
    {
    
    
        if(arr[j]==0)
        {
    
    
            ret[k++]=j+1;
            //*returnSize++;
        }
    }
    *returnSize=k;
    return ret;
}

Resumo: Para determinar o número de ocorrências de um determinado número (especialmente não ordenado) no array (para determinar se ele aparece ou não, o número de ocorrências é 0), você pode usar este método, que é o o mesmo que o princípio de classificação radix.O espaço é trocado pelo tempo, o que é obrigatório ao abrir o espaço.
 Acabou, acabou, espero que você ganhe alguma coisa, essa é a maior motivação da minha criação.

Acho que você gosta

Origin blog.csdn.net/qq_75270497/article/details/134701619
Recomendado
Clasificación