498. Travessia diagonal
-
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
-
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.
-
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 k 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.
![](https://img-blog.csdnimg.cn/e8c7e9375a1f4cd6aafd510db9783366.png)
Versão recursiva:
Versão iterativa:
59. Matriz Espiral II
-
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] .
Versão recursiva DFS:
Versão de iteração DFS:
73.Zeragem da matriz
-
1) Use duas matrizes booleanas rows[M] e 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)
-
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 .
![](https://img-blog.csdnimg.cn/9fd5108bc7a04d2b93cccf8e083b3174.png)
-
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.
![](https://img-blog.csdnimg.cn/60b1322c3fb94d118c1f22097f637d4e.png)
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
-
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
-
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.
-
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] e 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.
![](https://img-blog.csdnimg.cn/a7306713e4be4965be22a84ec7514834.png)
-
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] e matriz[j, i] .
![](https://img-blog.csdnimg.cn/3ab21cb875bb4a759f05c0e9aaf09fec.png)
![](https://img-blog.csdnimg.cn/0faa0a6b0a6446f6ab81a399872d0a67.png)
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
-
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 0ª 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
-
1) O mesmo que 118, primeiro gere a matriz triangular Yang Hui com rowIndex + 1 linha e, em seguida, retorne à linha rowIndex
![](https://img-blog.csdnimg.cn/74c7ad336dff485798e8586d463a7e47.png)
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.
-
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
![](https://img-blog.csdnimg.cn/f870e878c2c147e3aabd58b9fbbe50e2.png)
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
-
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
-
1) Use a lista internamente para receber, use o método correspondente de list.iterator() , use iterator.next(), iterator.hasNext() , o código é omitido.
-
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.
![](https://img-blog.csdnimg.cn/b55c1e0d769149c091a7656183bc42e8.png)
867.Transpor matriz
-
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
-
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.
-
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.
![](https://img-blog.csdnimg.cn/81a26ef7b55d487dadadfb29c6bcfc74.png)
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
-
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
![](https://img-blog.csdnimg.cn/92866aa356914c3ab4723717cedb925e.png)
363. O valor máximo da soma da área retangular não excede K
-
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 s 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
-
① 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:
![](https://img-blog.csdnimg.cn/f99aa8b0d8134d2db2944d474e6ea38e.png)
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:
Código de implementação:
![](https://img-blog.csdnimg.cn/4bbc383ef44c44ddb7c187890cbf66ed.png)
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 x !
![](https://img-blog.csdnimg.cn/dccb0bef0e114919a10c2250764f4b87.png)
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
-
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
-
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 )
-
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).
-
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 e R , deixe L e 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 .
![](https://img-blog.csdnimg.cn/f316f6e1c8f64edabbf96b73ed8253fd.png)