Na classificação por mesclagem, usamos a estratégia de dividir e conquistar. Na estratégia de dividir e conquistar, resolvemos um problema recursivamente, aplicando as três etapas a seguir em cada camada de recursão:
分解
: Divida o problema em alguns subproblemas, a forma dos subproblemas é a mesma do problema original, mas em uma escala menor.解决
: Resolva os subproblemas recursivamente. Se a escala do subproblema for pequena o suficiente, pare a recursão e resolva-o diretamente.合并
: Combine as soluções dos subproblemas na solução do problema original.Quando o subproblema é grande o suficiente para ser resolvido recursivamente, ele é chamado
递归情况
. Quando o subproblema se torna pequeno o suficiente para que não haja necessidade de recursão, a recursão "atingiu o fundo" e entrou基本情况
. Às vezes, além de subproblemas menores que são exatamente da mesma forma que o problema original, também é necessário resolver subproblemas que não são exatamente iguais ao problema original. A solução desses subproblemas é considerada como parte da etapa de fusão.
Desta vez vamos passar 最大子数组
e 数组最大元素
dividir e conquistar a estratégia para o entendimento profundo de dois casos
Aperitivo: o maior elemento da matriz
Há muitas
分治策略
maneiras de resolver o maior elemento da matriz. Resolver o problema da perspectiva do pensamento proporcionará a você um prazer diferente.
- Decomposição: divida a matriz em duas submatrizes esquerda e direita pelo meio e decompor recursivamente
- Solução: quando a matriz é indivisível, trate
基本情况
- Combine: compare os resultados retornados pelas submatrizes e retorne o valor máximo.
Código de amostra
private static int maxValue(int[] array,int start,int end){
if (start==end){
//数组不可分时,返回即为最大值
return array[start];
}
//计算中点
int mid = (start+end)/2;
//递归求解左右子数组最大值
int l = maxValue(array,start,mid);
int r = maxValue(array,mid+1,end);
//返回处理结果
return l>r?l:r;
}
Depois de servido o aperitivo, vamos pedir o prato principal para aprofundar seu entendimento?
Prato principal: o maior problema de submatriz
最大子数组
Refere-se a encontrar a submatriz contínua com a maior soma em uma matriz contendo números negativos. (Toda a matriz de números não negativos é a maior)
análise
Suponha que estamos procurando a maior submatriz de A [baixo, alto]. A estratégia de divisão e conquista significa que temos que dividir a submatriz em duas submatrizes do mesmo tamanho possível. Por exemplo, encontre a posição intermediária no meio da matriz e, em seguida, considere resolver as duas submatrizes A [baixa, média], A [média + 1, alta]. A posição de qualquer submatriz contínua A [i, j] de A [baixo, alto] deve ser uma das seguintes três situações:
左边最大
, Que está completamente em A [baixo, médio], baixo ≤ i ≤ j ≤ médio右边最大
, Que está completamente localizado em A [mid + 1, high], mid < i ≤ j ≤ high跨越中点
, 即 baixo ≤ i ≤ médio < j ≤ alto
Os dois primeiros são subproblemas da mesma forma, mas para a 跨越中点
situação, precisamos de soluções especiais
跨越中点
跨越中点
Para casos especiais, é necessário um processamento adicional: começando com o meio, calcule a posição acumulada e máxima do elemento à esquerda, calcule o máximo acumulado e a posição do elemento à direita e retorne a posição do elemento e as acumulações esquerda e direita. O código de amostra é o seguinte:
/**
* 计算跨越 mid 情况下的最大数组和
*
* @param array 待计算数组
* @param start 起始位置
* @param mid 中点位置
* @param end 结束位置
* @return int[最大子数组起始位置、最大子数组结束位置、最大子数组数值]
*/
private static int[] maxCrossSum(int[] array, int start, int mid, int end) {
int sum = 0;
int leftSum = Integer.MIN_VALUE;
int rightSum = Integer.MIN_VALUE;
int leftPos = 0, rightPos = 0;
//计算左侧累加最大值和位置
for (int i = mid; i >= start; i--) {
System.out.println("array ::: " + array[i]);
sum = sum + array[i];
if (sum > leftSum) {
leftSum = sum;
leftPos = i;
}
}
System.out.println("start --- mid : max left sum is " + leftSum + "; max left position is " + leftPos);
sum = 0;
//计算右侧累加最大值和位置
for (int i = mid + 1; i <= end; i++) {
System.out.println("array ::: " + array[i]);
sum = sum + array[i];
if (sum > rightSum) {
rightSum = sum;
rightPos = i;
}
}
System.out.println("mid --- end : max right sum is " + rightSum + "; max right position is " + rightPos);
//返回最大和数组
return new int[]{
leftPos, rightPos, leftSum + rightSum};
}
Solução global
Depois de lidar com a situação especial, podemos
分治策略
resolver o problema de acordo .
- Decomposição: Divida duas submatrizes no meio da matriz, decompõe o problema recursivamente. Compare as situações à esquerda, à direita e no ponto médio.
- Solução: quando o número de elementos da matriz for 1, insira
基本情况
e resolva o problema.- Combine: Combine os resultados dos subproblemas, determine o valor máximo e retorne o resultado.
Código de amostra:
/**
* 对于分析中的1、2两种情况,可以通过递归拆分为相同子问题,因为都是在求指定上限(start 和 end 是确定的)的最大和子数组问题。
* 第3种情况则特殊处理即可
*
* @param array 待计算数组
* @param start 数组起始位置
* @param end 数组结束位置
* @return int[最大子数组起始位置、最大子数组结束位置、最大子数组数值]
*/
private static int[] find(int[] array, int start, int end) {
//如果数组中只有一个元素,直接返回当前元素
if (end == start) {
System.out.println("end == start" + start + " array value = " + array[start]);
return new int[]{
start, end, array[start]};
}
int mid = (start + end) / 2;
//分别当前数组左侧最大值、右侧最大值、和包含 mid 最大值
int[] left = find(array, start, mid);
int[] right = find(array, mid + 1, end);
int[] cross = maxCrossSum(array, start, mid, end);
//比较最大值并返回
if (left[2] > right[2] && left[2] > cross[2]) {
return left;
} else if (right[2] > left[2] && right[2] > cross[2]) {
return right;
} else {
return cross;
}
}
Comecei a escrever quando voltei de uma viagem de negócios e finalmente cheguei aqui, hahaha, continue trabalhando duro! Próximo artigo "Heap Sorting of Sorting Algorithms"