알고리즘 - 연속 서브 - 어레이 최대 시작 첨자를 찾고

면책 조항 :이 문서는 블로거 원본입니다, 추적 에 의해-SA의 CC 4.0 저작권 계약, 복제, 원본 소스 링크이 문을 첨부 해주세요.
이 링크 : https://blog.csdn.net/red_sheeps/article/details/102767426

코드 GitHub의 실행을 참조하십시오
https://github.com/GloryXu/algorithm/tree/master/src/main/java/com/redsun/algorithm/subarraysum을

알고리즘 실수로 포럼 게시물을 발견했다 방문, 한 번 다음, 수집 정보를 검색, 더 나은 솔루션을 생각했다.
여기에 그림 삽입 설명

브 루트 포스

    @Override
    public void execute() {
        for (int i = 0; i < arr.length; i++) {
            // 遍历从i开始的所有子数组
            for (int j = i; j < arr.length; j++) {
                int thisSum = 0;

                // 累计求和
                for (int k = i; k <= j; k++) {
                    thisSum += arr[k];
                }
                if (thisSum > maxSum) {
                    // 记录最大子数组的位置和长度
                    maxSum = thisSum;
                    start = i;
                    end = j;
                }
            }
        }
    }

2 사이클 이외 다시 비교 합산 한 사이클은 최종 최대 서브 어레이를 얻었다.
최대 서브 어레이를 얻는 동시에, 상기 대응하는 기록 시작 및 종료 위치, 즉 최대 인덱스 서브 어레이에 대응.
알고리즘의 시간 복잡도O(n^3)

분 치료 방법

블록 1

    private int findMaxChildArr(int[] arr, int left, int right) {
        if (left == right) {
            // 如果左等于右,则说明这个子数组只存在一个元素,则返回它用于比较
            return arr[left];
        } else {
            // 递归思想
            int middle = (left + right) / 2;
            // 寻找左侧数组最大值;
            int leftMax = findMaxChildArr(arr, left, middle);
            // 寻找右侧数组最大值;
            int rightMax = findMaxChildArr(arr, middle + 1, right);
            // 寻找中间最大值
            int middleMax = findMiddleMax(arr, left, right, middle);
            // 比较求出值
            if (leftMax >= rightMax && leftMax >= middleMax) {
                return leftMax;
            } else if (rightMax >= leftMax && rightMax > middleMax) {
                return rightMax;
            } else {
                return middleMax;
            }
        }

    }

블록 2

    public int findMiddleMax(int[] arr, int left, int right, int middle) {
        int lmidMax = -1000;
        int rmidMax = -1000;
        int sum = 0;
        // 找到向左的最大前缀
        for (int i = middle; i >= left; i--) {
            sum += arr[i];
            if (sum > lmidMax) {
                lmidMax = sum;
            }
        }
        // 找到向右的最大后缀
        sum = 0;
        for (int i = middle + 1; i <= right; i++) {
            sum += arr[i];
            if (sum > rmidMax) {
                rmidMax = sum;
            }
        }
        return lmidMax + rmidMax;
    }
  1. 어레이가 2 등분하고 최대 배열 된 서브 어레이는 중간 오른쪽 (왼쪽 부, 우측 부)에, 좌측에 세 개의 케이스를 가질 수도
  2. 만큼 왼쪽 후 L1 최대 우측 R1, 최대 중간 M1, 즉 최대로, 결과는 전체 어레이의 최대 서브 어레이는
  3. 제 포인트로 복귀된다 (최대 R1의 우측)의 최대 좌측 L1을 추구하면, 다음 어레이는 좌측에 대응하는 분할하고, 최대 L2 (R2 최대 우측)을 탐색한다 (오른쪽) 남아있을 수 있고, 순차적으로 재귀 최종left=right
  4. 최대 값의 중간에 걸쳐에서 찾는 다른 방법 middle—>leftmiddle—>right참조 심지어 즉 최대 각각 최대 값을 찾고, 블록 2 .
    알고리즘의 시간 복잡도는 O(N*LogN)이분법 :( LogN) * (가운데 최대 값 N을 선택)의 복잡성의 개인 이해,
    가장 큰 하위 배열 첨자를 해결하는 방법을 생각하지 않았다 대응, 어린이 신발의지도하에있을 것입니다.

욕심쟁이 알고리즘

    @Override
    public void execute() {
        /**
         * sumStart ,sumEnd 分别表示累加数组的start位和end位
         * 也相当于 sumStart 是前一次计算结果,sumEnd 是后一次计算结果
         * 这里代码中潜在的关系是
         * sumEnd = sumStart + arr[end]
         */
        int sumStart = 0;
        int sumEnd = 0;
        int minStart = 0;// 表示最小的 minStart
        for (int endIndex = 0; endIndex < arr.length; endIndex++) {
             // 相当于构建累加数组 sumEnd 的过程,sumEnd[0..end] = sumEnd[0..end-1] + arr[end]
            sumEnd = sumEnd + arr[endIndex];
            // 寻找 minStart,minStart[j] = min(minStart[j-1],sum[0..j])
            if (sumStart < minStart) {
                minStart = sumStart;
                /**
                 * 如果此时sum[0..(endIndex - 1)](即sumStart) < minStart
                 * 则最大子数组的start只可能从endIndex开始
                 * 通俗一点就是endIndex(0~endIndex-1)之前的都已经被赋给minStart了
                 */
                this.start = endIndex;
            }
            // 更新 sumTotal
            if (sumEnd - minStart > maxSum) {
                maxSum = sumEnd - minStart;
                /**
                 * 如果maxSum值变动,说明最大子数组的end值为当前endIndex
                 */
                this.end = endIndex;
            }
            sumStart = sumStart + arr[endIndex];
        }
    }

여기에 그림 삽입 설명

  1. 이 연속적인 서브 어레이이기 때문에, 어레이는 화상 화학식의 시작과 끝이 만나는 존재한다
  2. 따라서, 두 해결 minStart 결국은 maxSum 진화, 즉, 코드 블록은 두 결정의 목적은

알고리즘은 최적의 솔루션의 현재 이해하고, 핵심 아이디어는 때마다 다시 시작하지 않고, 마지막주기의 결과를 사용하는 것입니다. 코드 매우 상세한 주석, 당신은주의 깊게 이해할 수있다.
한 번만 전체 배열, 시간 복잡도를 통과 O(N).

영업 실적

다음 작업의 최종 결과는
여기에 그림 삽입 설명

추천

출처blog.csdn.net/red_sheeps/article/details/102767426