问题描述:
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
问题解决思路:
小编为大家介绍三种处理此问题的办法:(具体的思路已经放在代码的注释中了,请大家细细阅读,不懂可以留言)
第一:暴力破解
第二:分治法
第三:动态规划
代码实现:
package Algorithm;
public class Example3 {
//暴力求解最大子数组和时间复杂度比较高
public int Violentsolution(int[] array){
int sum = -10000;//记录子数组的和
int low;//记录子数组的底
int high;//记录子数组的高
String result;
for (int i = 0; i < array.length; i++){//利用两层for循环遍历所有的子数组情况
for (int j = i; j < array.length; j++){
int arraysum = 0;//所遍历出来的子数组的和
for (int k = i; k <= j; k++){//i肯定比j大,i和j就是子数组的上下界
arraysum = arraysum + array[k];
}
if (arraysum > sum){
sum = arraysum;
low = i;
high = j;
}
}
}
return sum;
}
//用来比较三个数的大小
public int Max(int Maxleftsum,int Maxrightsum){
int max = -999999;
int MaxRLsum = Maxleftsum + Maxrightsum;
if (max < Maxleftsum){
max = Maxleftsum;
}
if (max < Maxrightsum){
max = Maxrightsum;
}
if (max < MaxRLsum){
max = MaxRLsum;
}
return max;
}
//分治法的实质就是将一个大问题分治为若干个独立的小问题,一般采用递归的思想
public int Divideconquer(int[] array, int left, int right ){//利用分治法求解最大子数组问题
if (left == right){//递归出口
return array[left];
}
int center = (right + left) / 2;
int Maxleftsum = Divideconquer(array, left, center);
int Maxrightsum = Divideconquer(array, center+1, right);
//计算左边子数组的值
int MaxleftBsum = 0,LeftBsum = 0;
for (int i = center; i >= left; i-- ){
LeftBsum += array[i];
if ( MaxleftBsum < LeftBsum){
MaxleftBsum = LeftBsum;
}
}
//计算右边子数组的值
int MaxrightBsum = 0,RightBsum = 0;
for (int j = center + 1; j <= right; j++){
RightBsum += array[j];
if ( MaxrightBsum > RightBsum){
MaxrightBsum = RightBsum;
}
}
return Max(Maxleftsum, Maxrightsum);
}
//动态规划解决最大子数组问题
public int DP(int array[]) {
int start = 0, end = 0;//初始化最大子数组的起始位置(在数组中的下标)
int Maxarray; //最大子数组的值
int[] dp = new int[array.length];//用于进行动态规划的记录
dp[0] = array[0];//将第一个数初始化为记录的第一条
Maxarray = dp[0];//将记录的第一条初始化为最大值
int temp = 0;
for (int i = 1; i < array.length; i++){
if (dp[i-1] <= 0){//前面的值<0,直接丢掉
dp[i] = array[i];
temp = i;//记录起始位置
}
else{
dp[i] = array[i] + dp[i-1];
}
if (dp[i] > Maxarray){//求解最大子数组的和,开始位置,结束位置
Maxarray = dp[i];
start = temp;
end = i;
}
}
return Maxarray;
}
public static void main(String[] args) {
int[] array = {-6, -8, 2, 1, 3, 0, -1};
Example3 object = new Example3();
System.out.print(object.DP(array));
}
}
总结:
动态规划也是一种分治思想(比如其状态转移方程就是一种分治),但与分治算法不同的是,分治算法是把原问题分解为若干个子问题,自顶向下求解子问题,合并子问题的解,从而得到原问题的解。动态规划也是把原始问题分解为若干个子问题,然后自底向上,先求解最小的子问题,把结果存在表格(这里的表格就是上面代码中的dp数组,请大家留意)中,在求解大的子问题时,直接从表格中查询小的子问题的解,避免重复计算,从而提高算法效率。