求最大子数组之和
蛮力法:
算法思路:找出所有子数组,然后求出子数组的和然后,在所有子数组的和中取最大值
时间复杂度:O(n^3) 优化后O(n^2)
代码实现:
/**
*
* 暴力法求最大子数组的和问题
* 时间复杂度n(n^3)
* @return
*/
public static int maxSubArray(int arr[]){
int n = arr.length;//数组大小
int ThisSum = 0;//记录主数组的和
int MaxSum = 0;//记录最大子数组的和
int i,j,k;
for (i=0;i<n;i++){//记录子数组的底
for(j=0;j<n;j++){//记录子数组的高
ThisSum =0;
for (k=0;k<j;k++){//计算所遍历出来的子数组的和
ThisSum+=arr[k];
}
if (ThisSum > MaxSum){//找出最大的子数组
MaxSum = ThisSum;
}
}
}
return MaxSum;
}
/**
* 时间复杂度O(n^2)
* @param arr
* @return
*/
public static int maxSubArray1(int arr[]){
int size = arr.length;
int maxSum = Integer.MIN_VALUE;
for(int i = 0; i<size; i++){
int sum = 0;
for (int j=i;j<size;j++){
sum+=arr[j];
if (sum>maxSum){
maxSum = sum;
}
}
}
return maxSum;
}
动态规划法:
算法思路:根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
1、最大子数组中包含arr[n-1],以arr[n-1]结尾
2、arr[n-1]单独构成最大子数组
3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
假设:
(arr[0],...,arr[i-1])的最大的一段数组和为nAll
(arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
得出关系:
nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}
时间复杂度: O(n)
代码实现:
/**
* 时间复杂度O(n)
* 方法描述:
* 根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
* 1、最大子数组中包含arr[n-1],以arr[n-1]结尾
* 2、arr[n-1]单独构成最大子数组
* 3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
*
* 假设:
* (arr[0],...,arr[i-1])的最大的一段数组和为nAll
* (arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
* 得出关系:
* nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}
*
* @param arr
* @return
*/
public static int maxSubArray2(int[] arr){
int n = arr.length;
int nAll = arr[0];
int nEnd = arr[0];
for (int i = 0; i < n; i++) {
nEnd = max(nEnd+arr[i], arr[i]);//单独的arr[i]与包含arr[i]的最大子数组和比较,较大值赋给nEnd
nAll = max(nEnd, nAll);//nEnd与不包含arr[i]的数组进行比较得出最终的最大值
}
return nAll;
}
/**
* 获取较大的值
* @param m
* @param n
* @return
*/
public static int max(int m ,int n){
return m>n?m:n;
}
扩展:确定最大子数组的位置
算法思路:当End[i-1]<0时,End[i]=array[i];子数组从i开始
代码实现:
private static int begin = 0;//最大子数组起始位置
private static int end = 0;//最大子数组结束位置
/**
* 确定最大子数组的位置
* @param arr
* @return
*/
public static int maxSubArray3(int arr[]){
int maxSum = Integer.MIN_VALUE;
int nSum = 0;
int nStart = 0;
for (int i = 0; i < arr.length; i++) {
if (nSum<0) {//End[i-1]<0,子数组从i重新开始
nSum = arr[i];
nStart = i;
}
else {
nSum += arr[i];
}
if (nSum > maxSum) {
maxSum = nSum;//记录最大子数组
begin = nStart;//此时子数组的开始值
end = i;//此时子数组的结束值
}
}
return maxSum;
}
}
完整代码为:
package JBArray;
public class MaxSubArrary {
private static int begin = 0;//最大子数组起始位置
private static int end = 0;//最大子数组结束位置
/**
* 确定最大子数组的位置
* @param arr
* @return
*/
public static int maxSubArray3(int arr[]){
int maxSum = Integer.MIN_VALUE;
int nSum = 0;
int nStart = 0;
for (int i = 0; i < arr.length; i++) {
if (nSum<0) {//End[i-1]<0,子数组从i重新开始
nSum = arr[i];
nStart = i;
}
else {
nSum += arr[i];
}
if (nSum > maxSum) {
maxSum = nSum;//记录最大子数组
begin = nStart;//此时子数组的开始值
end = i;//此时子数组的结束值
}
}
return maxSum;
}
/**
*
* 暴力法求最大子数组的和问题
* 时间复杂度n(n^3)
* @return
*/
public static int maxSubArray(int arr[]){
int n = arr.length;//数组大小
int ThisSum = 0;//记录主数组的和
int MaxSum = 0;//记录最大子数组的和
int i,j,k;
for (i=0;i<n;i++){//记录子数组的底
for(j=0;j<n;j++){//记录子数组的高
ThisSum =0;
for (k=0;k<j;k++){//计算所遍历出来的子数组的和
ThisSum+=arr[k];
}
if (ThisSum > MaxSum){//找出最大的子数组
MaxSum = ThisSum;
}
}
}
return MaxSum;
}
/**
* 时间复杂度O(n^2)
* @param arr
* @return
*/
public static int maxSubArray1(int arr[]){
int size = arr.length;
int maxSum = Integer.MIN_VALUE;
for(int i = 0; i<size; i++){
int sum = 0;
for (int j=i;j<size;j++){
sum+=arr[j];
if (sum>maxSum){
maxSum = sum;
}
}
}
return maxSum;
}
/**
* 时间复杂度O(n)
* 方法描述:
* 根据数组中最后一个元素arr[n-1]与最大子数组的关系分为以下三种情况:
* 1、最大子数组中包含arr[n-1],以arr[n-1]结尾
* 2、arr[n-1]单独构成最大子数组
* 3、最大子数组中不包含arr[n-1],求arr[1,...,n-1]的最大子数组转化为求arr[1,...,n-2]的最大子数组
*
* 假设:
* (arr[0],...,arr[i-1])的最大的一段数组和为nAll
* (arr[0],...,arr[i-1])包含arr[i-1]的最大的一段数组和为nEnd
* 得出关系:
* nAll = max{arr[i-1],nEnd(i-1),nAll(不包括arr[i-1]的最大子数组)}
*
* @param arr
* @return
*/
public static int maxSubArray2(int[] arr){
int n = arr.length;
int nAll = arr[0];
int nEnd = arr[0];
for (int i = 0; i < n; i++) {
nEnd = max(nEnd+arr[i], arr[i]);//单独的arr[i]与包含arr[i]的最大子数组和比较,较大值赋给nEnd
nAll = max(nEnd, nAll);//nEnd与不包含arr[i]的数组进行比较得出最终的最大值
}
return nAll;
}
/**
* 获取较大的值
* @param m
* @param n
* @return
*/
public static int max(int m ,int n){
return m>n?m:n;
}
public static void main(String[] args){
int[] arr = {1,-2,4,8,-4,7,-1,-5};
System.out.println(maxSubArray(arr));
System.out.println(maxSubArray2(arr));
}
}