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:
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
- 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.
- Complexidade de tempo: O(N(intervalo))
- 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
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.
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
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.
Pode-se descobrir que a maioria dos casos de uso foram aprovados
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.
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
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.