《算法导论》学习日记(二)

分治思想

求最大连续子数组和:

方法一:暴力法:

暴力法求最大和,就是利用循环将一个数组的无数组合可能性的和都求出来,进行比较,求出当下最大和的最大值
如代码中的第一个大循环,就是以i为起始,以j为结尾的元素下标,然后将所有以i为开头,以j为结尾的的数组的组合都求出来,算出来一个最大值,然后,以i+1,为开头,继续进行,直到所有的都算出来为止
比如说一个数组arr[1,2,-3],如图:
在这里插入图片描述


import java.util.Scanner;

public class baoli {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int k=sc.nextInt();
		//第一行输入原始数组的长度
		int[] arr=new int[k];
		//确定数组的长度
		for(int i=0;i<k;i++) {
			arr[i]=sc.nextInt();
		}
		//输入
		System.out.println(maxsum(arr));
	}
	public static int maxsum(int[] arr) {
		int max=0;
		int cur=0;
		int left = 0;
		int right = 0;
		//以每一个元素为开头,进行大量的重复
		//以i为循环累加的元素下标的开头,以j为结尾
		for(int i=0;i<arr.length;i++) {
			for(int j=i;j<arr.length;j++) {
				int arrsum=0;
				//arrsum即当前的最大和
				for(int k=i;k<=j;k++) {
					arrsum+=arr[k];
					//srrsum不断累加
				}
				if(arrsum>cur) {
					//arrsum达到最大值以后,将这个数值赋给cur
					cur=arrsum;
					//在当前停下的,就是起始值
					left=i;
					right=j;
				}
			}
		}
		
		for(int l=left;l<=right;l++) {
			max+=arr[l];
		}
		return max;
		
	}
}


方法二:神奇的方法

这个是从B站上学到的,附上链接,这个方法是设定两个值,一个cur,一个max,cur用来不断移动累加取得当前的最大值,并且当cur为负数的时候就重置为0,而max则是初始为最小值,也就是MIN_VALUE,之后与cur不断比较,存储cur的最大值,而最后,max的值就是最大和。
比如说一个数组arr[1,2,3,-4,-5,6,7],如图:

在这里插入图片描述

import java.util.Scanner;
public class zishuzu {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int k=sc.nextInt();
		//第一行输入原始数组的长度
		int[] arr=new int[k];
		//确定数组的长度
		for(int i=0;i<k;i++) {
			arr[i]=sc.nextInt();
		}
		//输入
		System.out.println(maxsum(arr));
		
	}
	public static int maxsum(int[] arr) {
		if(arr==null||arr.length==0) {
			return 0;
		}
		
		int max=Integer.MIN_VALUE;
		//max是最小值
		int cur=0;
		//cur的起始值为0
		for(int j=0;j!=arr.length;j++) {
			cur+=arr[j];
			//cur不断累积
			max=Math.max(max, cur);
			//没累加一次就与max进行一次比较,max为二者中最大的数
			cur=cur<0?0:cur;	
			//cur如果一旦小于0.就重置归零
		}
		return max;		
	//最后返回的max就是最大子数组之和
	}
}

方法三:分治法:

分治法是《算法导论》本章很重要的一个知识点,但是。。。嗯。。。菜鸡发现道理我都懂,代码不会写,后参考大神代码理解。
分治法求最大和就是寻找到最大连续子数组,只要找到这个最大连续子数组,就可以求和了,而最大连续子数组的位置,按照分治思想有三种可能性:1.在原始数组的左端部分,2.在原始数组的中间位置,3.在原始位置的右部分
所以从中间位置划分,开始游览,左边部分与右边部分的最大和的,而中间位置其实就是左右部分的最大值的相加, 递归相加即可。
比如说一个数组:arr[]={1,2,-3,-4,-5,6,7,-8,-9,-10},如图:
在这里插入图片描述


import java.util.Scanner;

public class fenzhi {
	//三个部分进行比较
	public static int max3(int a, int b ,int c) {
        int max=a;
        if(b>max) {
            max=b;
        }
        if(c>max) {
            max=c;
        }
        return max;
    }
    
    public static int findmaxSubSum(int[] arr,int left, int right) {
        int maxLeftSum,maxRightSum; //左边和右边最大和
        int maxLeftBorderSum, maxRightBorderSum; //含中间边界的左右部分最大和
        int leftBorderSum, rightBorderSum; //含中间边界的左右部分当前和的值
        int i,center;
        //如果左右下标相等,左右相加的时候,返回一个左边的
        if(left == right) {          
                return arr[left];         
        }
        
        center = (left + right)/2;
        //中间值,从这里开始
        
        //找出左部最大值
        maxLeftBorderSum =0;
        leftBorderSum =0;
        for(i=center;i>=left;i--) {
            leftBorderSum += arr[i];
            //让左边部分定义的这个和不断进行累加
            if(leftBorderSum > maxLeftBorderSum) {
            	//并将最大值赋给
                maxLeftBorderSum = leftBorderSum;
            }
        }
        
        //找出右部最大值
        maxRightBorderSum =0;
        rightBorderSum =0;
        for(i=center+1;i<=right;i++) {
            rightBorderSum +=arr[i];
            if(rightBorderSum>maxRightBorderSum) {
                maxRightBorderSum = rightBorderSum;
            }
        }
        
        //递归求左右部分最大值
        maxLeftSum =findmaxSubSum(arr, left, center);
        maxRightSum = findmaxSubSum(arr, center+1, right);
        //左部分,右部分,中间值跨界部分
        return max3(maxLeftSum, maxRightSum, maxLeftBorderSum+maxRightBorderSum);
    }
    
    public static int maxSubSum(int arr[],int len) {
        return findmaxSubSum(arr, 0, len-1);
        //数组的长度、数组左部分,即left,数组右部分,即right
    }
    
    public static void main(String[] args) {
    	Scanner sc=new Scanner(System.in);
		int k=sc.nextInt();
		//第一行输入原始数组的长度
		int[] arr=new int[k];
		//确定数组的长度
		for(int i=0;i<k;i++) {
			arr[i]=sc.nextInt();
		}
		
        System.out.println(maxSubSum(arr, k));
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值