Algoritmo divide e conquista estratégia e aplicação

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"

Acho que você gosta

Origin blog.csdn.net/lijie2664989/article/details/83514446
Recomendado
Clasificación