《算法导论》第4章最大子数组Java实现

一个数组的最大子数组是指该数组的一个和最大的子数组

最大子数组有三种分布情况:
         1 最大子数组完全在数组的左半部
         2 最大子数组完全在数组的右半部
         3 最大子数组跨越数组的中间分布在左右半部,该情况又可分为1 2 3三种子情况
其中前两种分布情况是和主问题相同的子问题,可以使用递归分治去解决,而第三种情况和主问题形式不同,需要考虑继续拆分为三种情况。        
 

由于Java不支持元组形式,因此使用一个result数组保存子数组的信息,result[0]为子数组的下标起点low,result[1]为子数组下标终点high,result[2]为子数组的和sum。

用三个result数组分别保存三种分布情况

result0保存第一种完全在左半部,result1保存第二种完全在右半部,result2保存第三种跨越数组中间。

代码如下:

public class MaxSumSubArray {

	public static void main(String[] args) {
		int a[]= {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7,1000};
        int result[] = Find_MaxiMum_SubArray(a, 0, a.length-1);
        int low = result[0];
        int high = result[1];
        int subsum = result[2];
        System.out.println("数组为:");
        for(int i:a) {
        	System.out.print(i+" ");
        }
        System.out.println();
        System.out.println("最大子数组起始下标low:"+low+",最大子数组终止high:"+high+",最大子数组和subsum:"+subsum);
        System.out.println("最大子数组为:");
        for(int i=low;i<=high;i++) {
        	System.out.print(a[i]+" ");
        }
	}
	
	/*最大子数组问题
                      一个数组的最大子数组是指该数组的一个和最大的子数组
                     最大子数组有三种分布情况:
         1 最大子数组完全在数组的左半部
         2 最大子数组完全在数组的右半部
         3  最大子数组跨越数组的中间分布在左右半部,该情况又可分为1 2 3三种子情况
         
                  用result数组保存子数组的信息,result[0]为子数组的下标起点low,result[1]为子数组下标终点high,result[2]为子数组的和sum
	*/
	//寻找最大子数组和
	public static int[] Find_MaxiMum_SubArray(int[] A,int low,int high) {
		//result1保存第1种情况,result1[0]为left_low,result1[1]为left_high,result1[2]为left_sum
		int[] result1 = new int[3];
		//result2保存第2种情况,result2[0]为right_low,result2[1]为right_high,result2[2]为right_sum
		int[] result2 = new int[3];
		//result3保存第3种情况,result3[0]为cross_low,result3[1]为cross_high,result3[2]为cross_sum
		int[] result3 = new int[3];
		if(low==high) {
			result1[0] = low;
			result1[1] = high;
			result1[2] = A[low];
			return result1;
		}else {
			int mid = (low+high)/2;
			result1 = Find_MaxiMum_SubArray(A, low, mid);
			result2 = Find_MaxiMum_SubArray(A, mid+1, high);
			result3 = Find_Max_Crossing_SubArray(A, low, mid, high);
			if(result1[2]>=result2[2]&&result1[2]>=result3[2]) {
				return result1;
			}else if(result2[2]>=result1[2]&&result2[2]>=result3[2]) {
				return result2;
			}else {
				return result3;
			}
		}
		
	}
	
	//最大子数组横跨中点时的情况
	private static int[] Find_Max_Crossing_SubArray(int A[],int low,int mid,int high) {
		int left_sum = -9999999;//保存左半子数组的最大和
		int sum = 0;//保存当前的最大和
		int max_left=0;//保存左半子数组最大和时的左下标
		for(int i=mid;i>=low;i--) {
			sum=sum+A[i];
			if(sum>left_sum) {
				left_sum = sum;
				max_left = i;
			}
		}
		
		int right_sum = -9999999;//保存右半子数组的最大和
		sum =0;//保存当前的最大和
		int max_right=0;//保存右半子数组最大和时的左下标
		for(int j=mid+1;j<=high;j++) {
			sum = sum+A[j];
			if(sum>right_sum) {
				right_sum=sum;
				max_right = j;
			}
		}
		//用一个结果数组来保存值,result[0]为左子数组的下标,result[1]为右子数组的下标,result[2]为横跨中点的子数组最大的值
		int result[] = {max_left,max_right,left_sum+right_sum};
		return result;
	}

}

结果为:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值