[Notas do exame LeetCode] Matriz bidimensional

498. Travessia diagonal

Ideias para resolução de problemas:
  • Para simplificar o problema, primeiro considere imprimir os elementos na diagonal, um por um, sem considerar a inversão.
  • Uma matriz bidimensional com M linhas e N colunas tem um total de M + N - 1  linhas diagonais ( canto superior direito -> canto inferior esquerdo )
  • 1) Como percorrer: Percorra o número de diagonais  da esquerda para a direita , percorrendo M + N - 1  rodadas no total, d: [0, M + N - 1 ) Determine o canto superior direito da diagonal atual d em cada rodada As coordenadas (x, y) do ponto , então use este ponto como ponto de partida, inicie um loop while e siga o método x++, y-- , ou seja, a direção superior direita -> inferior esquerda, atravesse a matriz localizado no ponto diagonal e salve-o na matriz de resultados res[i++] =  array[x][y] , a condição de julgamento do loop while : x < M && y >= 0  , ou seja, se nenhum deles cruza o limite, ele continuará a fazer um loop até cruzar o limite.
  • 2) Como salvar a polilinha: Quando d%2 == 0,  você precisa salvá-la ao contrário, para poder fazer uma lista neste momento e salvá-la com Collections.reverse(list) ou iniciar o interno loop while de percorrer a diagonal toda vez Escreva a posição atual do array res como start . No final do loop while , o i  subscrito de res é a posição final. Apenas inverta o intervalo de res[start...i ]  (você pode escrever uma função para reverter o intervalo da matriz aqui).
  • 3) Como determinar as coordenadas do ponto do canto superior direito da linha diagonal d : Na verdade, os pontos do canto superior direito de todas as linhas diagonais são aqueles pontos localizados na linha superior e na coluna mais à direita de toda a matriz, então, quando d < N , então As coordenadas x são todas 0 , e as coordenadas y são d , ou seja,  [ 0, d] . Quando d >= N , as coordenadas x dos pontos procurados são  d - ( N - 1 ) , e as coordenadas y são todas N - 1 , ou seja [ d - ( N - 1 ) , N - 1] .  

Como mostrado abaixo: 

A maior dificuldade nesta questão é primeiro observar que o número de diagonais direitas de uma matriz bidimensional é M + N - 1 , pois este é o número de voltas de diagonais que queremos percorrer. Em segundo lugar, precisamos determinar as coordenadas (x, y) do canto superior direito de cada linha diagonal e calculá-las de forma equivalente usando o subscrito diagonal. (Ora, porque estamos atravessando a diagonal, não podemos obter as coordenadas bidimensionais de cada ponto neste momento, então precisamos converter)

 Para ver mais claramente, removemos todos os números da matriz:

 

Na verdade, as coordenadas do ponto inicial diagonal da linha superior são os pontos coordenados da primeira linha da matriz bidimensional. Suas abcissas são todas 0 e a ordenada é o subscrito da coluna da matriz bidimensional para isso ponto, que pode ser considerado como ( 0, j) , mas quando percorremos, percorremos o número de rodadas diagonais [0, M + N - 1] , em vez de percorrer a matriz bidimensional como o duplo for loop geral ( se for esse o caso, pode obter i e j ), então as coordenadas do ponto inicial da diagonal da primeira linha precisam ser calculadas de forma equivalente usando o número redondo subscrito da diagonal, que é exatamente ( 0, d) .

Da mesma forma, o ponto inicial da diagonal da última coluna é na verdade o ponto coordenado (i, N - 1) da última coluna da matriz bidimensional . Também precisamos usar o subscrito da diagonal para calculá-la de forma equivalente, que é (d - (N - 1), N - 1) .

Por fim, ao salvar a resposta, você precisa usar um pequeno truque, ou seja, o valor d=0, 2, 4...na diagonal ímpar (ou o subscrito da diagonal é Ou seja, a linha diagonal azul na imagem acima deve ficar assim:

 

 

54. Matriz espiral 

Ideias para resolução de problemas:
  • 1) Acesso por camada/anel : acesso cíclico às quatro bordas das bordas superior, direita, inferior e esquerda. Deixe 4 variáveis ​​representarem os limites superior, inferior, esquerdo e direito respectivamente: T = 0, B = M - 1, eu = 0, R = N - 1 ,
  • Primeiro, use um loop while na camada mais externa para controlar as quatro direções sem cruzar o limite:  T < B && L < R ,
  • Em seguida, em cada loop, use 4 loops for para coletar os valores nas quatro bordas dos lados superior, inferior, esquerdo e direito, respectivamente. Após a coleta, as quatro bordas encolhem para dentro em um círculo ao mesmo tempo T  ++ B-- L++ R-- ,
  • Ao finalmente sair do loop while , haverá apenas uma linha  T==B  ou uma coluna  L==R left , basta coletá-las. 

Como mostrado abaixo: 

 

Por exemplo, ao coletar a linha acima, use um loop for para percorrer o intervalo i:  [L, R) .A abcissa neste momento é fixada em T , e o subscrito de travessia é a coordenada da coluna, portanto, o valor de cada elemento no loop for está array[ T][i] . Da mesma forma, para a coleção  i à direita:  [T, B) , o valor do elemento é matriz[i][R] ; para a coleção i:  [R, L) abaixo  , o valor do elemento é matriz[ B][ i] ; para a coleção esquerda  i:  [B, T)  , o valor do elemento é array[i][L] .

Quando finalmente encolher para a camada mais interna, restará apenas uma linha ou coluna, conforme mostrado na figura a seguir:

Uma coisa a se notar no código acima é que quando resta apenas uma linha ou coluna, ela só pode ser escrita na forma de if...else if... , e não pode ser escrita na forma de dois ifs julgados lado a lado. Porque para uma matriz quadrada como a questão do exemplo 1, restará apenas um ponto no final. Neste momento, T==B ou L==R será satisfeito ao mesmo tempo. Se estiver escrito na forma de dois  ifs julgados lado a lado, esse ponto será coletado mais uma vez, levando a respostas erradas.

Ideias para resolução de problemas:
  • 2) Travessia DFS : começando em (0,0) , pressione  DFS nas quatro direções direita, inferior, esquerda e superior e defina uma matriz de direção bidimensional int [][]  dirs = { { 0 , 1 } ,   {1, 0} ,  {0, -1}, {-1, 0} } e a matriz booleana[][] visitada , colete o nó atual a cada vez e marque-o como visitado e, em seguida, calcule o próximo nó x + dirs[k][0], y +  dirs[k][1]  , onde representa a direção e o k inicial == 0. Depois de coletar os nós em cada recursão, primeiro determine se o próximo ponto está fora dos limites ou foi visitado . Se não estiver fora dos limites e não tiver sido visitado, faça uma chamada recursiva e, se sair dos limites ou tiver sido visitado, mude a direção k = ( k + 1 )% 4 e, em seguida, recalcular o valor do próximo nó novamente (nota).  
  • Ele pode ser implementado usando loops ( tempos MXN de loop ) ou modelos padrão de função recursiva dfs.

Versão recursiva:

Versão iterativa:

59. Matriz Espiral II

 

Ideias para resolução de problemas:
  • O mesmo que 54, primeiro crie uma matriz bidimensional e substitua o local onde você obtém o valor de matriz[x][y] na questão 54 pela atribuição de um valor a matriz[x][y] .
Pressione o anel para acessar as versões:

Versão recursiva DFS: 

Versão de iteração DFS: 

73.Zeragem da matriz

 

Ideias para resolução de problemas:
  • 1) Use duas matrizes  booleanas rows[M]  cols[N]  para registrar se cada linha e cada coluna precisam ser definidas como  0 ,
  • Primeiro percorra a matriz. Se array[i][j] == 0 , registre rows[i] = true  e cols[j] = true .
  • Finalmente, itere pela matriz novamente . Se  rows[i] ou  cols[j] for true defina array[i][j]  como 0 .
  • A complexidade espacial deste método é O(m+n)

Ideias para resolução de problemas: 
  • 2)  Use a 0ª linha e a 0ª coluna da matriz original como duas matrizes de marcadores para registrar se uma linha ou coluna diferente da primeira linha e coluna precisa ser definida como 0.
  • Duas variáveis ​​precisam ser usadas antecipadamente para marcar se a linha 0 e a coluna 0 contêm 0 ,
  • Em seguida, percorra a matriz primeiro e comece o processamento a partir da posição [1,1] . Se matriz[i][j] == 0 , atualize  matriz[i][0] == 0 (esta linha precisa ser definida como 0) e matriz[ 0][j] == 0 (esta coluna precisa ser definida como 0)  
  • Em seguida, percorra a matriz novamente , comece o processamento a partir da posição [1,1] e determine se matriz[i][0] == 0 ou  matriz[0][j] == 0 e, em seguida, defina matriz[i][j ]  0 .  
  • Após a conclusão do processamento final, se a linha 0 e a coluna 0 precisam ser definidas como 0 , serão processadas apenas com base nas duas primeiras variáveis ​​de marca
Ideias para resolução de problemas:  
  • 3) Otimização para o método 2: ainda use a 0ª linha e a 0ª coluna da matriz original e , em seguida, use apenas uma variável para marcar se a 0ª coluna precisa ser definida como 0 e percorra tudo , exceto a 0ª coluna , começando pela última linha em ordem inversa Cada elemento é processado em paralelo, evitando assim que o elemento da linha 0 seja atualizado antecipadamente (a linha 0 será processada por último). Este método salva apenas uma variável.

O ponto chave desta questão é que você não pode definir a posição anterior como 0 primeiro, porque o comportamento de "definir todas as linhas e colunas como 0" afetará o julgamento da posição subsequente. Se uma determinada posição na última posição for devido ao anterior O processamento de julgamento de posição é definido como 0 antecipadamente e, quando usado posteriormente, será o valor após ser substituído. Desta forma, um julgamento preciso não pode ser feito posteriormente e é muito provável que a matriz seja definido como 0. Portanto, precisamos encontrar um local adicional para registrar a marca "se uma determinada linha ou coluna precisa ser definida como 0".A idéia simples é que o método 1 use duas matrizes adicionais para registrar (espaço O(m+n)) , e economiza espaço com mais eficiência.A ideia é usar parte da matriz original para registrar, ou seja, método 2 e método 3 (espaço O(1)).

289.Jogo da Vida

Ideias para resolução de problemas:
  • Como o valor de cada elemento da matriz é apenas 0 ou 1 , o bit binário de cada elemento da matriz pode ser usado para representar o estado composto ,
  • Use os 2 bits inferiores 00 do inteiro de 32 bits , onde os bits inferiores são usados ​​para representar o estado original e os bits superiores são usados ​​para representar o estado modificado .
  • Percorra a matriz , encontre o número de células vivas nas oito direções em torno de cada posição (usando a técnica de matriz dirs ) e, em seguida, modifique o valor dos bits de ordem superior dos 2 bits binários inferiores de cada elemento de acordo com as regras de a pergunta .
  • Se você precisar alterar uma célula morta para uma célula viva , você só precisa executar a operação num | 10  para definir a posição como 1. Se você precisar mudar uma célula viva para uma célula morta , a posição alta não precisa a ser movido ( porque o valor original é apenas 0 ou 1, apenas os bits mais baixos são usados, portanto, os bits mais altos são padronizados como 0, 01 ou 00 ).
  • Nota: O valor do elemento é usado diretamente ao julgar o estado original, porque cada elemento da matriz percorrida é acessado pela primeira vez e não foi modificado, e a modificação consiste em modificar os bits de ordem superior do elemento bits binários. Porém, ao calcular o número de células vivas nas oito direções ao redor do elemento atual, você deve usar num & 1 para julgar, ou seja, olhar apenas para o estado original de seus bits baixos , porque os elementos nas oito direções podem ter foi modificado.
  • Finalmente, percorra a matriz novamente e altere cada elemento para o valor dos bits de ordem superior de seus dois bits binários de ordem inferior (por meio da operação >>1   ).

Esta questão é muito semelhante à questão 73, ou seja, você precisa primeiro encontrar um local para armazenar o valor do estado modificado e depois modificar a matriz de acordo com a marca do estado armazenado. No entanto, a questão requer modificação no local, então você só pode modificá-lo na matriz original.Esta questão usa os bits binários livres do valor do elemento (os elementos da questão são apenas 1 ou 0).

48. Girar imagens

 

Ideias para resolução de problemas:
  • 1) A mesma ideia da matriz espiral 54, acessada por camada/anel/círculo , definindo quatro limites de direção T = 0, B = N - 1, L = 0, R = N - 1
  • A condição do loop externo é L < R (ou  T < B ). Em cada loop, os valores dos elementos localizados nas quatro bordas são trocados respectivamente. O número de trocas controladas pelo loop é R - L ou B - T , e a troca é concluída.Finalmente, a camada externa encolhe para dentro, ou seja, T++, B--, L++, R-- .
  • Nota: Ao trocar elementos, faça -o no sentido horário (você deve primeiro reservar os poços na ordem e prosseguir para trás)
  • O valor do elemento superior deve ser colocado na   matriz mais à direita[T][L+i] ->  matriz[T+i][R] ,
  • O valor do elemento mais à direita deve ser colocado na parte inferior array[T+i][R] ->  array[B][Ri]  
  • O valor do elemento inferior deve ser colocado na  matriz mais à esquerda[B][Ri] ->  matriz[Bi][L] ,
  • O valor do elemento mais à esquerda deve ser colocado na  matriz superior[Bi][L] ->  matriz[T][L+i] 

 Conforme mostrado na figura acima, embora o efeito de troca seja no sentido horário, ao realmente trocar códigos, você precisa primeiro se lembrar de um lado, deixar um poço e, em seguida, preencher o poço no sentido anti-horário.

 

Observe que no código acima, a condição de saída do loop while é L < R , mas comparado com a questão 54, não há necessidade de lidar com a situação de L==R (ou T==B ).Isso ocorre porque a entrada desta questão é um quadrado nxn . Matriz, as características desta matriz são:

  • 1) Ou  L==R sai no final. Neste momento, ainda resta um ponto no meio. Naturalmente, não há necessidade de continuar a troca. Por exemplo, este é o caso de uma matriz 3x3.
  • 2) Ou  L > R  sai no final. Neste momento, todas as trocas na matriz foram concluídas e não sobrou nada. Por exemplo, este é o caso de uma matriz 4x4.
Ideias para resolução de problemas: 
  • 2) Primeiro espelhe e vire ao longo da diagonal esquerda , depois espelhe e vire para a esquerda e para a direita ao longo da linha vertical do eixo central .
  • A operação específica de inversão diagonal do espelho: percorra a metade inferior esquerda da matriz i: [0, N), j: [0, i) e troque matriz[i, j] matriz[j, i] .
  • A operação específica de inversão do espelho esquerdo e direito: percorrer a metade esquerda da matriz   i: [0, N), j: [0, N / 2) , trocar matriz[i j] e   matriz[i N - j - 1]  , isso é Can. 

Ideias para resolução de problemas:
  • 3) Primeiro espelhe para cima e para baixo ao longo da linha horizontal do eixo central e depois espelhe ao longo da diagonal esquerda .
  • A operação específica de virar o espelho para cima e para baixo: percorrer a metade superior da matriz  i: [0, N / 2), j: [0, N) , trocar  matriz[i, j] e   matriz[N - i - 1 , j]  , isso é Can.
  • A operação específica de inversão diagonal do espelho: percorra a metade inferior esquerda da matriz i: [0, N), j: [0, i) e troque matriz[i, j] matriz[j, i] .

 Na verdade, essa pergunta pode ser feita invertendo imagens  espelhadas para a esquerda e para a direita + invertendo imagens espelhadas na diagonal para a direita ou  invertendo imagens espelhadas na diagonal para a direita + invertendo imagens espelhadas para cima e para baixo. Você pode descobrir por meio da observação. Mas as coordenadas da diagonal direita não são tão convenientes quanto as da diagonal esquerda durante a troca.

118.Igreja Evangélica

Ideias para resolução de problemas:
  • Converta o problema em uma matriz bidimensional alinhada à esquerda para pensar. O valor atual = o valor da linha anterior + o valor do canto superior esquerdo 
  • Na i -ésima linha, a e a última colunas são  1 e as demais satisfazem  res[i][j] = res[i - 1][j] + res[i - 1][j - 1 ]
  • Processe-o percorrendo o loop for de duas camadas da matriz. O número de linhas da matriz é N dado na questão , e o número de colunas da matriz : a i-ésima linha tem i + 1 colunas , então j: [0, i] (i começa em 0)

 

Se você achar List problemático, poderá usar diretamente uma matriz bidimensional para calcular e depois transferi-la novamente, mas também é problemático:

119.Igreja Evangélica

 

Ideias para resolução de problemas:
  • 1) O mesmo que 118, primeiro gere  a matriz triangular Yang Hui com rowIndex + 1  linha e, em seguida, retorne à  linha rowIndex 

Ideias para resolução de problemas: 

  • 2) Use uma matriz contínua para lembrar a linha anterior. Após cada atualização da linha atual, atribua a linha atual à linha anterior.

 

Ideias para resolução de problemas: 
  • 3) Use uma matriz, atualize da direita para a esquerda em cada linha e calcule na ordem inversa começando na coluna j = i, res[j] = res[j] +  res[j - 1], res[0] inicial = 1

Neste momento, quando a linha atual não foi atualizada, a própria matriz é considerada como o valor restante da linha anterior. O valor na posição atual é na verdade o valor na linha acima da posição atual, e o valor na posição atual posição anterior é na verdade o valor antes da linha anterior. O valor do local.

36. Sudoku eficaz

Ideias para resolução de problemas:
  • Use 3 matrizes de marcadores booleanos para marcar se 1-9 aparece em cada linha, cada coluna e cada grade 3x3 da matriz original.
  • Digitalize cada número na matriz bidimensional para determinar se ele apareceu nessas 3 matrizes de marcas. Se apareceu, viola as regras do Sudoku e retorna false ; se não apareceu, coloque-o nessas 3 matrizes de cada tag está marcado como verdadeiro .
  • Nota: Ao percorrer a matriz, os espaços (ou seja, os caracteres ' . ') são ignorados e apenas os caracteres numéricos são processados.

Para cada linha de números de 1 a 9, a definição é a seguinte: 

 

Por que é uma matriz booleana bidimensional 9x9 aqui? Como a matriz original tem 9 linhas, o comprimento unidimensional é 9, e em cada linha precisamos representar a existência de um total de 9 números de 1 a 9, então 9 são necessários em cada linha Matriz de comprimento.

Para colunas, a representação é semelhante:

 

Para uma grade pequena 3x3, uma matriz booleana tridimensional[3][3][9] é obviamente necessária.

251.Expandir vetores bidimensionais

Ideias para resolução de problemas:
  • 1) Use a lista internamente para receber, use o método correspondente de  list.iterator()  , use iterator.next(), iterator.hasNext() , o código é omitido.
Ideias para resolução de problemas:
  • 2)  Ponteiros duplos usam duas variáveis ​​row e col para apontar para índices subscritos unidimensionais e bidimensionais, respectivamente.Quando a camada interna chega ao final, a linha é quebrada e a próxima camada col começa do início, pulando as linhas vazias.

 

867.Transpor matriz

Ideias para resolução de problemas:
  • Para uma matriz com M linhas e N colunas, crie um array res com N linhas e M colunas ( as linhas e colunas são trocadas ) e, em seguida, percorra a matriz e salve-a. res[j][i] = matriz[i] [j] troque as  coordenadas da linha e da coluna ao salvar . É isso aí
  • Observe a diferença de [ 48. Girar imagem ] . A matriz de rotação é uma rotação no sentido horário. Esta questão é apenas um giro do espelho ao longo da diagonal superior esquerda-inferior direita.

Você pode imaginar apertar o canto inferior esquerdo do cartão com os dedos e, em seguida, virá-lo em direção ao canto superior direito ao longo da linha diagonal superior esquerda-inferior direita.

Por que a matriz de resultados aqui tem N linhas e M colunas? Porque a matriz da questão não é necessariamente quadrada. Por exemplo, na matriz 3x2 da figura abaixo, matriz[2][0] deve ser armazenada em matriz[0 ][2] após a inversão.Se o resultado As linhas e colunas da matriz estiverem desalinhadas e obviamente não podem ser salvas.

 

Claro, você também pode escrever de outra maneira, e trocar os subscritos pelos valores da matriz original de acordo com a forma de percorrer a matriz de resultado:

 

304. Recuperação de soma de região bidimensional - matriz imutável

Ideias para resolução de problemas:
  • 1) Matriz de soma de prefixo bidimensional , usando a ideia de encontrar a área , defina S(i, j) para representar a área do retângulo na matriz bidimensional com [0, 0] como o superior canto esquerdo e [i, j] como canto inferior direito,
  • Então há  S(i, j) = S(i - 1, j) + S(i, j - 1) - S(i - 1, j - 1) + matriz[i][j]  
  • Portanto sumRegion(x1, y1, x2, y2) = S(x2, y2) - S(x1-1, y2) - S(x2, y1-1) + S(x1-1, y1-1) 

Cada grade na matriz de soma de prefixo bidimensional registra "a posição atual é o canto inferior direito da área e o canto superior esquerdo da área é sempre a soma da área do canto superior esquerdo da matriz original". sinto que não está claro, altere S[i] [j] é entendido como a soma da área com  (i, j)  como o canto inferior direito e (0, 0) como o canto superior esquerdo.

O diagrama de S[ i, j é o seguinte:

O diagrama de S[ i - 1, j é o seguinte:

O diagrama de S[ i, j - 1 é o seguinte:

 

O diagrama de S[ i - 1, j - 1 é o seguinte:

 

Então, juntos obtemos:

 

 S[ i, j é equivalente a  S[ i - 1, j ] + S[ i, j - 1 ] + matriz[i, j] mas um S[ i - 1, j - 1 é adicionado várias vezes . Portanto, é necessário subtrair S[ i - 1, j - 1  

Com a fórmula de cálculo de  S[ i, j , escaneamos a matriz original e calculamos o valor de S[ i, j ]  para cada grade , obtendo assim uma matriz bidimensional de soma de prefixos. Quando exigimos (x1, y1) como o canto superior esquerdo e (x2, y2) como a soma da área do canto inferior direito, podemos usar diretamente a matriz de soma de prefixos para resolver rapidamente: 

A soma da área de [x1, y1] a [x2, y2] é equivalente à soma da área com [x2, y2] como o canto inferior direito menos a soma da área acima com [x1 - 1, y2] como o canto inferior direito. e, em seguida, subtraia a soma da área à esquerda com [x2, y1 - 1] como o canto inferior direito, mas a soma da área com [x1 - 1, y1 - 1] como o canto inferior direito é subtraído várias vezes, é necessário adicionar a soma da área anterior com [x1 - 1, y1 - 1] como o canto inferior direito.

 Observe que, para facilitar o cálculo e o processamento das condições de contorno, o prefixo e o comprimento da matriz são adicionados por 1 , o que equivale a adicionar uma linha em branco com todos os valores 0 à esquerda e no topo de a matriz original. Esta é a ideia da programação defensiva. Neste momento, o significado de prefixSum[i][j] é representar a soma cumulativa da área bidimensional composta pelas primeiras i linhas e as primeiras j colunas (contando a partir de 1 ) na matriz original. Ou seja, o subscrito em prefixSum significa número, portanto, ao calcular sumRegion , você pode converter o subscrito do índice do parâmetro em um subscrito numérico, para que corresponda à fórmula de cálculo resumida anteriormente.

Ideias para resolução de problemas: 
  • 2)  Encontre a soma do prefixo de cada linha e encontre uma matriz de soma de prefixo para cada linha. Existem matrizes de soma de prefixo M em linhas M. Ao encontrar sumRegion , você realmente percorre cada linha de [ row1... row2] e use a linha A diferença entre o prefixo e a matriz é usada para encontrar a soma dos intervalos [ col1...col2 ] da linha e, em seguida, os resultados de cada linha são acumulados.

 Esta ideia é mais simples que o método 1. (Embora o método 1 seja mais eficiente ao encontrar sumRegion)

308. Região 2D e recuperação - variável

 

Ideias para resolução de problemas:
  • Encontre a soma do prefixo de cada linha , o mesmo que o método 2 da pergunta 304 , use a diferença da soma do prefixo para encontrar a soma regional, mas há um método de atualização adicional . Ao atualizar, só precisamos adicionar o prefixo ao coluna col da linha

 

363. O valor máximo da soma da área retangular não excede K

 

Ideias para resolução de problemas:
  • Compactar um array bidimensional em um array unidimensional (técnicas de compactação de array)
  • O loop for externo percorre cada linha de   [0, M - 1]  , marcada s abaixo da linha e cria uma matriz unidimensional arr com o mesmo comprimento que o número de colunas de cada vez  , que é usada para salvar  o resultado da compactação da linha [s..i]  .
  • O loop interno seleciona a linha   atual como a linha inicial a cada vez , percorre [s, M - 1] e acumula a i- ésima linha atual em  arr  a cada vez . Neste momento, arr  contém apenas os elementos da linha s a linha i. e (ou seja, as linhas s..i agora estão compactadas em uma linha ). Então, cada vez que na matriz unidimensional arr compactada pelas linhas si..i , basta encontrar  a soma cumulativa máxima das submatrizes  ≤ k .  

Na verdade, esse processo começa na linha 0 e aumenta 1 linha a cada vez até que as linhas, incluindo todas as linhas, sejam compactadas em uma linha. Resolva na linha compactada: 

 

Desta forma, todas as áreas retangulares a partir da linha 0 serão digitalizadas e ninguém será perdido.

O processamento a partir da linha 1, a partir da linha 2 e a partir da linha 3 é semelhante, e a solução é resolvida após cada compactação:

 Através do processo acima, podemos primeiro escrever o código do processo principal:

Agora, só nos resta uma última pergunta, que é como implementar o método getMaxNearK() no código acima

Existem vários métodos para encontrar a soma cumulativa máxima de submatrizes ≤ k na  matriz unidimensional arr :  
1) Você pode encontrar a soma cumulativa dos prefixos por meio de força bruta :
  • ① Primeiro calcule o valor máximo max da soma cumulativa na matriz unidimensional . Se max não exceder k , basta retornar max diretamente . Não há necessidade de continuar pesquisando.
  • ② Caso contrário, um loop for de camada dupla é usado para calcular violentamente a soma cumulativa de cada subintervalo. A enumeração externa   i: [0, N - 1] começa com  cada i e a enumeração interna j: [i, N - 1]  each No final de j , o loop interno acumula continuamente  arr[j]  em sum . Como j é enumerado a partir de  i , toda vez que sum é atualizado , obtemos um acúmulo de intervalos [i...j] . e, neste momento julgamos que se soma ≤ k for satisfeita , basta registrar o valor máximo.

Código de implementação: 

Deixe-me explicar um pouco mais no primeiro loop for do código acima, quando soma <= 0, por que deveríamos começar a acumular a partir do número atual novamente: porque se soma for um número negativo, [continuar acumulando o número atual] não seja melhor do que [usar apenas o próprio número atual] como soma cumulativa] o benefício é maior (há um pouco de ganância aqui). Por exemplo, soma = -10, arr[i] = -5. Se você continuar a acumular, a renda não aumentará, mas diminuirá. Para outro exemplo, soma = -10, arr[i] = 12, se acumulado, o resultado é 2, mas se arr[i] for tomado diretamente sem acumulação, obtém-se 12.

2) A maneira clássica de resolver a soma cumulativa de submatrizes é usar a diferença entre o prefixo e a matriz . Portanto, podemos primeiro calcular o prefixo e a matriz para arr e, em seguida, dobrar os loops for enumerar os subintervalos de cada prefixo e matriz, e a enumeração externa i: [0, N - 1] , enumeração interna j: [0, i] , use prefixSum[i + 1] - prefixSum[j] para obter a soma cumulativa do intervalo [ i...j] , juiz É suficiente se ≤ k .

Código de implementação:  

3) Substitua o prefixo e a matriz por uma lista ordenada TreeSet , apenas uma camada de for loop , adicione a soma cumulativa atualmente atualizada à lista ordenada a cada vez e encontre o valor mínimo ≥ sum - k  na lista ordenada find , If esse valor existe, registre soma -  o valor máximo encontrado  é o que você procura .  
 

Código de implementação:   

 

Nota: Na lista ordenada TreeSet , TreeSet.ceiling(x) retorna  o valor mínimo >=x  e mais próximo de x ! floor(x) retorna o valor máximo <=x  e mais próximo de  !  

Explique por que estamos procurando   TreeSet.ceiling(sum - k) acima . Para entender isso, precisamos primeiro entender o que está armazenado em TreeSet  . TreeSet  é na verdade equivalente ao prefixo e à matriz prefixSum no método 2) acima  , no qual o armazenado Cada elemento é o valor em prefixSum  . Dessa forma, consideramos a soma atualmente acumulada como prefixSum[i + 1] . O que exigimos é  prefixSum[i + 1] - prefixSum[j] ≤ k . Essa desigualdade é convertida em  prefixSum[j] ≥ prefixSum[i + 1] - k , para  encontrar um número no TreeSet  , que é   ≥ sum - k . Você pode consultar a imagem abaixo para entender:

 

Portanto, pode-se considerar que o método 3) é essencialmente equivalente ao método 2), mas usa algumas APIs de pesquisa convenientes da estrutura de dados avançada (árvore vermelha e preta), como TreeSet , para simplificar a camada dupla no método 2) . a pesquisa em loop apenas melhora a eficiência da pesquisa.

Entre os três métodos para calcular a soma cumulativa máxima de submatrizes ≤ k em uma matriz unidimensional, acho que o método 2) é o melhor para entender, e o método 3) é uma versão melhorada do método 2), mas devido à quantidade de dados na questão Não muitos, o método de força bruta do método 1) é o mais eficiente (o menos demorado entre as versões Java enviadas no LeetCode). Quando a quantidade de dados for grande, o método 3) será mais eficiente .

A complexidade mínima de tempo desta questão pode chegar a O(N^3).Se a força bruta for usada, pode exigir O(N^6). (Porque encontrar a submatriz requer O(N^4) para encontrar e depois percorrer a soma é O(N^2))

Uma pergunta de entrevista semelhante a esta:

Dada uma matriz bidimensional de inteiros, retorne a soma cumulativa máxima das submatrizes.

Ideia de resolução de problemas: esta questão é mais simples do que a questão original. Não há  limite de ≤ k. A ideia principal é a mesma acima. Podemos calcular diretamente o valor máximo da soma cumulativa durante a compactação. Não há necessidade de calcular separadamente o valor cumulativo máximo de ≤ k. E.

O código de implementação é o seguinte:

Aqui, quando  soma < 0 , a soma  é zerada para manter o benefício máximo da soma cumulativa, pois o benefício da soma cumulativa obtido ao continuar acumulando um número negativo com um determinado número não será maior que o benefício de apenas tomar o próprio número como a soma cumulativa (ganancioso). Exemplos específicos estão listados no método 1) entre os três métodos para calcular a soma cumulativa máxima de submatrizes ≤ k em uma matriz unidimensional. Você pode lê-lo.

348. Design Jogo da Velha

 

Ideias para resolução de problemas:
  • Use três matrizes bidimensionais para registrar o número de peças de xadrez colocadas pelo jogador X em cada linha, cada coluna e cada diagonal. Em cada método de movimento , adicione a contagem nas três matrizes correspondentes ao jogador atual + 1 , se o count em uma matriz atinge N , então o jogador vence e o número de série do jogador é retornado.
  • Dica: Na matriz de NXN , o ponto cujo ponto coordenado satisfaz i == j  está localizado na  diagonal principal (superior esquerdo-inferior direito), e o ponto cujo ponto coordenado satisfaz i + j == N - 1  está localizado em  a subdiagonal (superior direito-inferior esquerdo).)

296. Melhor ponto de encontro

 

Ideias para resolução de problemas:
  • 1. Classificação + mediana , a distância de Manhattan é na verdade a soma dos subproblemas de duas variáveis ​​​​independentes . Portanto, desde que resolvamos o caso unidimensional , podemos tratar o caso bidimensional como a soma de dois subproblemas unidimensionais independentes .
  • A mediana é o ponto de encontro ideal . Desde que haja o mesmo número de pontos à esquerda e à direita do ponto de encontro, a distância total é mínima .
  • Primeiro, percorremos a matriz original e processamos apenas a grade com valor 1. Coletamos as coordenadas das linhas e das colunas de cada grade em uma matriz unidimensional e as classificamos . Em seguida, selecionamos os elementos no meio delas e calcule dois independentes.A distância de Manhattan da matriz dimensional, a soma dos dois é a resposta.

 

Complexidade de tempo O ( mnlogmn ) 

Ideias para resolução de problemas:
  • 2. Colete coordenadas + mediana em ordem , o mesmo que o método 1, exceto que ao coletar os subscritos das colunas de cada grade com valor 1 , podemos coletar primeiro percorrendo as colunas e depois percorrendo as linhas , para que coletemos o os subscritos das colunas já estão classificados em ordem , eliminando assim a complexidade de tempo da operação de classificação. A complexidade do tempo é O(mn).

 

Ideias para resolução de problemas:
  • 3. Colete coordenadas + ponteiros de colisão em ordem , o mesmo que o método 2, exceto que ao calcular a distância de Manhattan de uma matriz unidimensional, você não precisa mais saber a mediana, você só precisa definir um par de  R , deixe R  se aproximarem de ambas as extremidades da matriz para o meio e acumular continuamente a diferença numérica points[R] -  points[L] em ambas as extremidades  .
Observe que esta questão é muito semelhante a [ 317. A distância mais próxima do edifício ]. A maior diferença entre as duas é que  a matriz na questão 317 contém obstáculos, portanto 317 só pode ser resolvida  usando BFS , não o método de 296.

 

Acho que você gosta

Origin blog.csdn.net/lyabc123456/article/details/133501807
Recomendado
Clasificación