您的位置:首页 > 编程语言 > Java开发

[leetcode]分治法求解最大子序列问题——Java实现

2014-08-27 19:45 706 查看

</pre>问题描述:</h1><p></p><p style="margin-top:0px; margin-bottom:10px; color:rgb(51,51,51); font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; font-size:14px; line-height:30px">Find the contiguous subarray within an array (containing at least one number) which has the largest sum.</p><p style="margin-top:0px; margin-bottom:10px; color:rgb(51,51,51); font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; font-size:14px; line-height:30px">For example, given the array <code style="font-family:Monaco,Menlo,Consolas,'Courier New',monospace; font-size:13px; padding:2px 4px; color:rgb(199,37,78); white-space:nowrap; background-color:rgb(249,242,244)">[−2,1,−3,4,−1,2,1,−5,4]</code>,<br style="" />the contiguous subarray <code style="font-family:Monaco,Menlo,Consolas,'Courier New',monospace; font-size:13px; padding:2px 4px; color:rgb(199,37,78); white-space:nowrap; background-color:rgb(249,242,244)">[4,−1,2,1]</code> has the largest sum = <code style="font-family:Monaco,Menlo,Consolas,'Courier New',monospace; font-size:13px; padding:2px 4px; color:rgb(199,37,78); white-space:nowrap; background-color:rgb(249,242,244)">6</code>.</p><span style="font-family:SimHei; font-size:18px">本例一般有两种解法,第一种被称为Kadane's Algorithm,使用O(n)时间。第二种是利用分支策略(Divide-Conquer),时间复杂度为O(nlogn)。主要描述第二种方法Java实现,思路来自算法导论第四章分治策略。</span><p><span style="font-family:SimHei; font-size:18px">分治主要分为三个步骤:</span></p><p><span style="font-family:SimHei; font-size:18px">分解(Divide):将问题划分为一些子问题,其形式与原问题相同,只是规模更小。</span></p><p><span style="font-family:SimHei; font-size:18px">解决(Conquer):递归求解子问题。如果子问题规模足够小,则停止递归,直接求解。</span></p><p><span style="font-family:SimHei; font-size:18px">合并(Combine):将子问题的解合并成原问题的解。</span></p><p><span style="font-family:SimHei; font-size:18px"></span></p><p><span style="font-family:SimHei; font-size:18px">分析本问题,一个数组可以看做由其左右子数组构成,而其最大子序列必定为以下三种情况之一:</span></p><p><span style="font-family:SimHei; font-size:18px">1. 在其左子数组中</span></p><p><span style="font-family:SimHei; font-size:18px">2. 在其右子数组中</span></p><p><span style="font-family:SimHei; font-size:18px">3. 横跨左右子数组</span></p><p><span style="font-family:SimHei; font-size:18px"></span></p><p><span style="font-family:SimHei; font-size:18px">因此,根据此分类可到的分治法主程序如下:</span></p><p><span style="font-family:SimHei; font-size:18px"></span></p><pre name="code" class="java">private int[] findMaxSubarray(int[] A, int low, int high) {
        int[] results = new int[3];//初始化返回数组results,包含最大子数组的low,high和sum
        int[] resultsleft, resultsright, resultscross;
        int mid;
        if (low == high) {
            //基本情况(base case):只有单个元素
            results[0] = low;
            results[1] = high;
            results[2] = A[low];
            return results;
        } else {
            //递归情况(recursive case)
            mid = (low+high) / 2;
            resultsleft = findMaxSubarray(A, low, mid);//递归求解左子序列
            resultsright = findMaxSubarray(A, mid+1, high);//递归求解右子序列
            resultscross = findMaxCrossSubarray(A, low, mid, high);//求解横跨左右子序列的情况
            //比较三种结果,取大者返回
            if (resultsleft[2] >= resultsright[2] && resultsleft[2] >= resultscross[2]) return resultsleft;
            else if (resultsright[2] >= resultsleft[2] && resultsright[2] >= resultscross[2]) return resultsright;
            else return resultscross;
        }
        
    }


求解很跨左右子序列情况的方法如下:

private int[] findMaxCrossSubarray(int[] A, int low, int mid, int high) {
int[] results = new int[3];
double leftsum = -1.0 / 0.0;//初始化左部分最大数组和为负无穷
double rightsum = -1.0 / 0.0;//初始化右部分最大数组和为负无穷
double sum = 0;
int maxleft = mid;
int maxright = mid + 1;
for (int i = mid; i >= low; i--) {
//从mid到low计算连续子数组和sum
sum = sum + A[i];
if (sum > leftsum) {
//如果sum比左部分最大数组和大,则更leftsum为sum并记录下标为maxleft
leftsum = sum;
maxleft = i;
}
}

sum = 0;
for (int i = mid+1; i <= high; i++) {
//右子数组处理与左子数组相同
sum = sum + A[i];
if (sum > rightsum) {
rightsum = sum;
maxright = i;
}
}
results[0] = maxleft;
results[1] = maxright;
results[2] = (int)(leftsum + rightsum);
return results;
}


引导程序如下:

public int maxSubArray(int[] A) {
int[] results;
results = findMaxSubarray(A, 0, A.length - 1);
return results[2];
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: