Esta é uma questão de lição de casa. Eles dizem que leva O(logN + logM)
onde N
e M
são os comprimentos das matrizes.
Vamos nomear os arrays a
e b
. Obviamente, podemos ignorar todos a[i]
e b[i]
onde i> k.
Primeiro, vamos comparar a[k/2]
e b[k/2]
. Deixe b[k/2]
> a[k/2]
. Portanto, podemos descartar também todos b[i]
, onde i> k / 2.
Agora temos all a[i]
, onde i <k e all b[i]
, onde i <k / 2 para encontrar a resposta.
Qual é o próximo passo?
arrays
algorithm
binary-search
Michael
fonte
fonte
O(logN + logM)
referindo apenas ao tempo que leva para encontrar o k-ésimo elemento? O pré-processamento pode ser feito para o sindicato com antecedência?Respostas:
Você tem isso, apenas continue! E cuidado com os índices ...
Para simplificar um pouco, assumirei que N e M são> k, então a complexidade aqui é O (log k), que é O (log N + log M).
Pseudo-código:
Para a demonstração, você pode usar o invariante de loop i + j = k, mas não farei todo o seu dever de casa :)
fonte
Espero não estar respondendo ao seu dever de casa, pois já se passou mais de um ano desde que essa pergunta foi feita. Aqui está uma solução recursiva final que levará tempo log (len (a) + len (b)).
Premissa: as entradas estão certas. ou seja, k está no intervalo [0, len (a) + len (b)]
Casos básicos:
Etapas de redução:
a
+ índice médio deb
for menor quek
a
for maior do que o elemento médio deb
, podemos ignorar a primeira metade deb
, ajustark
.a
, ajustek
.k
for menor que a soma dos índices médios dea
eb
:a
for maior que o elemento médio deb
, podemos ignorar com segurança a segunda metade dea
b
Código:
Observe que minha solução é criar novas cópias de arrays menores em cada chamada; isso pode ser facilmente eliminado apenas passando os índices de início e fim nos arrays originais.
fonte
kthlargest()
retorna(k+1)
-ésimos menores elementos, por exemplo,1
é o segundo menor elemento,0,1,2,3
ou seja, seus retornos de funçãosorted(a+b)[k]
.Muitas pessoas responderam a esta pergunta "k ésimo menor elemento de duas matrizes classificadas", mas geralmente com apenas idéias gerais, não um código de trabalho claro ou análise de condições de contorno.
Aqui eu gostaria de elaborá-lo cuidadosamente com a maneira que fiz para ajudar alguns novatos a entender, com meu código Java de trabalho correto.
A1
eA2
são duas matrizes ascendentes classificadas, comsize1
esize2
como comprimento, respectivamente. Precisamos encontrar o k-ésimo menor elemento da união dessas duas matrizes. Aqui, supomos razoavelmente que(k > 0 && k <= size1 + size2)
, o que implica issoA1
eA2
não pode ser vazio.Primeiro, vamos abordar essa questão com um algoritmo lento O (k). O método consiste em comparar o primeiro elemento de ambas as matrizes
A1[0]
eA2[0]
. Leve o menor, digamosA1[0]
, para o nosso bolso. Em seguida, compareA1[1]
comA2[0]
e assim por diante. Repita esta ação até que nosso bolso alcance osk
elementos. Muito importante: na primeira etapa, só podemos nos comprometerA1[0]
no nosso bolso. NÃO podemos incluir ou excluirA2[0]
!!!O código O (k) a seguir fornece um elemento antes da resposta correta. Aqui eu o uso para mostrar minha ideia e condição de contorno de análise. Eu tenho o código correto após este:
A ideia mais poderosa é que, em cada loop, sempre usamos a abordagem do caso base. Depois de comprometer o menor elemento atual, chegamos um passo mais perto do destino: o k-ésimo menor elemento. Nunca pule para o meio e fique confuso e perdido!
Observando o caso base do código acima
k == 1, k == size1+size2
, e combine com eleA1
eA2
ambos não podem estar vazios. Podemos transformar a lógica abaixo em um estilo mais conciso.Aqui está um código de trabalho lento, mas correto:
Agora podemos tentar um algoritmo mais rápido executado em O (log k). Da mesma forma, compare
A1[k/2]
comA2[k/2]
; seA1[k/2]
for menor, todos os elementos deA1[0]
aA1[k/2]
devem estar em nosso bolso. A ideia é não se comprometer apenas com um elemento em cada loop; a primeira etapa contémk/2
elementos. Novamente, NÃO podemos incluir ou excluirA2[0]
deA2[k/2]
qualquer maneira. Portanto, na primeira etapa, não podemos ir além dosk/2
elementos. Para a segunda etapa, não podemos ir além dek/4
elementos ...Após cada etapa, chegamos muito mais perto do k-ésimo elemento. Ao mesmo tempo, cada etapa fica cada vez menor, até chegarmos
(step == 1)
, que é(k-1 == index1+index2)
. Então, podemos nos referir novamente ao caso básico simples e poderoso.Aqui está o código de funcionamento correto:
Algumas pessoas podem se preocupar se
(index1+index2)
pular k-1? Podemos perder o caso básico(k-1 == index1+index2)
? Isso é impossível. Você pode somar 0,5 + 0,25 + 0,125 ... e nunca irá além de 1.Claro, é muito fácil transformar o código acima em algoritmo recursivo:
Espero que a análise acima e o código Java possam ajudá-lo a entender. Mas nunca copie meu código como seu dever de casa! Felicidades ;)
fonte
else if (A1[size1 - 1].compareTo(A2[size2 - 1]) < 0)
vez deelse if (A1[size1 - 1].compareTo(A2[size2 - 1]) > 0)
? (No código kthSmallestSlowWithFault)Aqui está uma versão iterativa C ++ da solução de @ lambdapilgrim (veja a explicação do algoritmo lá):
Funciona para todos os
0 <= n < (size(a) + size(b))
índices e temO(log(size(a)) + log(size(b)))
complexidade.Exemplo
fonte
Minha tentativa para os primeiros k números, k-ésimo número em 2 matrizes classificadas e em n matrizes classificadas:
O código completo com utilitários de depuração pode ser encontrado em: https://github.com/brainclone/teasers/tree/master/kth
fonte
Este é meu código baseado na solução de Jules Olleon:
fonte
Aqui está minha implementação em C, você pode consultar a explicação de @Jules Olléon para o algoritmo: a ideia por trás do algoritmo é que mantemos i + j = k, e encontramos tais i e j de modo que a [i-1] <b [j-1] <a [i] (ou vice-versa). Agora, uma vez que existem i elementos em 'a' menores que b [j-1] e elementos j-1 em 'b' menores que b [j-1], b [j-1] é i + j-1 + 1 = k ésimo menor elemento. Para encontrar tal i, j, o algoritmo faz uma pesquisa dicotômica nas matrizes.
fonte
Aqui está minha solução. O código C ++ imprime o menor valor k, bem como o número de iterações para obter o menor valor k usando um loop, que em minha opinião está na ordem de log (k). O código, entretanto, requer que k seja menor do que o comprimento da primeira matriz, o que é uma limitação.
fonte
O primeiro pseudo código fornecido acima não funciona para muitos valores. Por exemplo, aqui estão duas matrizes. int [] a = {1, 5, 6, 8, 9, 11, 15, 17, 19}; int [] b = {4, 7, 8, 13, 15, 18, 20, 24, 26};
Não funcionou para k = 3 ek = 9 nele. Eu tenho outra solução. É apresentado a seguir.
Mas ... também não está funcionando para k = 5. Existe essa captura par / ímpar de k que não permite que seja simples.
fonte
fonte
Aqui está a minha solução em java. Tentaremos otimizá-lo ainda mais
Isso é inspirado em Algo em um vídeo maravilhoso do youtube
fonte
Link para a complexidade do código (log (n) + log (m))
Link para o código (log (n) * log (m))
Implementação da solução (log (n) + log (m))
Eu gostaria de acrescentar minha explicação ao problema. Este é um problema clássico em que temos que usar o fato de que os dois arrays estão classificados. recebemos duas matrizes classificadas arr1 de tamanho sz1 e arr2 de tamanho sz2
a) Vamos supor que
Verificando se k é válido
então não podemos encontrar o menor elemento k na união de ambos os arrays classificados ryt Portanto, retorne dados inválidos. b) Agora, se a condição acima for falsa e tivermos um valor válido e viável de k,
Gerenciando Casos Extremos
Vamos anexar ambos os arrays por valores -infinity na frente e valores + infinito no final para cobrir os casos extremos de k = 1,2 ek = (sz1 + sz2-1), (sz1 + sz2) etc.
Algoritmo Principal
Agora, faremos uma pesquisa binária em arr1. Faremos uma pesquisa binária em arr1 procurando um índice i, startIndex <= i <= endIndex
de modo que se encontrarmos o índice j correspondente em arr2 usando a restrição {(i + j) = k}, então se
Uma vez que sabemos que o k - ésimo menor elemento tem (k-1) elementos menores que ele na união de ambas as matrizes ryt? Assim,
No Caso 1 , o que fizemos, que há um total de (k-1) elementos menores em arr1 [i] porque os elementos menores que arr1 [i] na matriz arr1 são em número i-1 do que sabemos (arr2 [ j-1] <arr1 [i] <arr2 [j]) e o número de elementos menores que arr1 [i] em arr2 é j-1 porque j é encontrado usando (i-1) + (j-1) = (k -1) Portanto, o menor elemento k será arr1 [i]
Mas a resposta nem sempre pode vir do primeiro array, isto é, arr1, então verificamos o caso 2, que também satisfaz de forma semelhante ao caso 1 porque (i-1) + (j-1) = (k-1). Agora, se tivermos (arr1 [i-1] <arr2 [j] <arr1 [i]), temos um total de k-1 elementos menores que arr2 [j] na união de ambas as matrizes, portanto é o k-ésimo menor elemento.
No caso 3 , para formar qualquer um dos casos 1 ou 2, precisamos incrementar i e j serão encontrados de acordo com a restrição {(i + j) = k} ou seja, na busca binária, mova para a parte direita, ou seja, faça startIndex = middleIndex
No caso 4 , para formá-lo em qualquer um dos casos 1 ou 2, precisamos decrementar i e j serão encontrados de acordo com a restrição {(i + j) = k} ou seja, na busca binária, mova para a parte esquerda, ou seja, faça endIndex = middleIndex .
Agora, como decidir startIndex e endIndex no início da pesquisa binária em arr1 com startindex = 1 e endIndex = ??. Precisamos decidir.
Porque se k é maior que o tamanho do primeiro array, podemos ter que fazer uma busca binária em todo o array arr1, caso contrário, só precisamos pegar os primeiros k elementos dele porque sz1-k elementos nunca podem contribuir no cálculo do k-ésimo menor.
CÓDIGO mostrado abaixo
Para solução de complexidade (log (n) * log (m))
Perdi a vantagem do fato de que para cada i o j pode ser encontrado usando a restrição {(i-1) + (j-1) = (k-1)} Portanto, para cada ii foi aplicando ainda mais a pesquisa binária na segunda matriz para encontrar j tal que arr2 [j] <= arr1 [i]. Portanto, esta solução pode ser otimizada ainda mais
fonte
Basicamente, por meio dessa abordagem, você pode descartar k / 2 elementos em cada etapa. O K mudará recursivamente de k => k / 2 => k / 4 => ... até atingir 1. Portanto, a complexidade do tempo é O (logk)
Em k = 1, obtemos a menor das duas matrizes.
O código a seguir está em JAVA. Observe que estamos subtraindo 1 (-1) no código dos índices porque o índice do array Java começa em 0 e não em 1, por exemplo. k = 3 é representado pelo elemento no 2º índice de uma matriz.
fonte
A complexidade de tempo é O (log (min (n, m)))
fonte
A maioria das respostas que encontrei aqui se concentra em ambos os arrays. embora seja bom, mas é mais difícil de implementar, pois há muitos casos extremos que precisamos cuidar. Além disso, a maioria das implementações são recursivas, o que adiciona a complexidade do espaço da pilha de recursão. Portanto, em vez de focar nos dois arrays, decidi focar apenas no array menor e fazer a pesquisa binária apenas no array menor e ajustar o ponteiro para o segundo array com base no valor do ponteiro do primeiro Array. Pela implementação a seguir, temos a complexidade de
O(log(min(n,m))
com a complexidade doO(1)
espaço.Temos um intervalo de
[low, high]
array fora
e estreitamos esse intervalo à medida que avançamos no algoritmo.sizeA
mostra quantos itens dek
itens são da matriza
e deriva do valor delow
ehigh
.sizeB
é a mesma definição, exceto que calculamos o valor de forma quesizeA+sizeB=k
. Com base nos valores dessas duas bordas, concluímos que devemos estender para o lado direito na matriza
ou encolher para o lado esquerdo. se preso na mesma posição que significa que encontramos a solução e vamos devolver o máximo de valores na posição desizeA-1
partira
esizeB-1
deb
.fonte
Verifique este código.
fonte
Abaixo do código C # para encontrar o k-ésimo menor elemento na união de duas matrizes classificadas. Complexidade de tempo: O (logk)
fonte
midA
partir deendA
ifk < n
. Verifique se há matrizes curtas, começando comreturn B[startB + k - 1];
.)