最大子数组问题(递归)(java)

最大子数组问题(递归)

作为分治策略的典型应用,时间复杂度可达到O(nlgn),与归并排序相同。
分治策略应用三种步骤:
分解:将问题分解成子问题,子问题的形式跟原问题一样,但规模更小,如果所解决的问题不能够分解,则分治也无从谈起。
解决:不断递归,子问题被分解为更小规模的子问题,直到递归“触底”,这解决该问题,即停止递归,递归开始“上升”。
归并:将各子问题的解合成其父问题的解

以问题“最大子数组”为例:
分解:将数组“均匀”分为两半,原问题即分解为:
1:找出左半边数组的子数组的最大值
2:找出右半边数组的子数组的最大值
3:找出跨越中点的子数组的最大值
解决:当数组分解到只剩一个值的时候,此时其子数组的最大值即唯一元素,返回该元素,结束递归
归并:归并即将三种问题的解归并,在这里,则则是找出三种返回结果的最大值

该题如果加上限制条件:要求输出结果非负(即结果为负数时返回0)
可设计程序时间复杂度为O(n),见函数getMax(int[] arr)

附代码:

public class LIANBIAO {


    public static void main(String[] args) {
         //int[] A = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
        int[] A = {-7,-2,3,-4};
        System.out.println(getMaxSubarray(A,0,A.length-1));
        //System.out.println(getMax(a));
    }
    
    public static int  getMax(int[] arr){

        int len = arr.length;
        int res = 0;
        int max = 0;
        for(int i=0;i<len;i++){
            res +=arr[i];
            if(res>max){
                max = res;
            }
            //如果结果已经为负数
            if(res<0){
                res = 0;
            }
        }
        return max;
    }
 
    //跨中点的最大子数组和的得出
    public static int getMaxCrossarray(int[] A,int low,int mid,int high){

        int maxleft = Integer.MIN_VALUE;
        int sumleft = 0;
        for(int i=mid;i>=low;i--){
            sumleft+=A[i];
            if(maxleft<sumleft){
                maxleft = sumleft;
            }
        }

        int maxRight = Integer.MIN_VALUE;
        int sumRight = 0;
        for(int i = mid+1;i<=high;i++){
            sumRight+=A[i];
            if(maxRight<sumRight){
                maxRight = sumRight;
            }
        }

        return maxleft+maxRight;

    }

    public static int getMaxSubarray(int[] A,int low,int high){
        if(low==high){
            return A[low];
        }
        int mid = (low+high)/2;
        int leftMax = getMaxSubarray(A,low,mid);
        int rightMax = getMaxSubarray(A,mid+1,high);
        int crossMax = getMaxCrossarray(A,low,mid,high);
        //合并
        if(leftMax>=rightMax&&leftMax>=crossMax){
            return leftMax;
        }else if(rightMax>=leftMax&&rightMax>=crossMax){
            return rightMax;
        }else{
            return crossMax;
        }

    }


}

### Java 实现最大子数组算法 #### 动态规划解法 为了求解给定整数数组中的最大子数组,可以采用动态规划的方法。此方法通过维护两个变量`maxSoFar``currentMax`来追踪遍历过程中的最大子数组以及包含当前元素的最大子数组[^5]。 ```java public class Solution { public int maxSubArray(int[] nums) { if (nums == null || nums.length == 0) { throw new IllegalArgumentException("Input array is empty or null"); } int currentMax = nums[0]; int maxSoFar = nums[0]; for (int i = 1; i < nums.length; ++i) { // 更新包含当前位置的最大子数组 currentMax = Math.max(nums[i], currentMax + nums[i]); // 更新全局最大子数组 maxSoFar = Math.max(maxSoFar, currentMax); } return maxSoFar; } } ``` 这段代码首先处理特殊情况即输入为空的情况;接着初始化`currentMax``maxSoFar`为第一个元素值。随后进入循环迭代剩余元素,在每次迭代时更新这两个变量直到完成整个数组扫描并最终返回最大子数组。 #### 分治法解法 另一种解决方案是利用分治策略解决问题。这种方法将原问题分解成更小规模的相同类型的子问题,并递归地解决这些子问题最后合并结果得到原始问题的答案。对于寻找最大子数组问题来说,则需考虑跨越中间位置的可能性: - 左边部分的最大子数组; - 右边部分的最大子数组; - 跨越中心点两侧的部分组成的新的可能的最大子数组。 具体实现如下所示[^4]: ```java class MaxSubArray { private int lSum, rSum, mSum, iSum; public MaxSubArray(int lSum, int rSum, int mSum, int iSum) { this.lSum = lSum; this.rSum = rSum; this.mSum = mSum; this.iSum = iSum; } } public class DivideAndConquerSolution { private static MaxSubArray pushUp(MaxSubArray l, MaxSubArray r) { int iSum = l.iSum + r.iSum; int lSum = Math.max(l.lSum, l.iSum + r.lSum); int rSum = Math.max(r.rSum, r.iSum + l.rSum); int mSum = Math.max(Math.max(l.mSum, r.mSum), l.rSum + r.lSum); return new MaxSubArray(lSum, rSum, mSum, iSum); } private static MaxSubArray getInfo(int[] a, int l, int r) { if (l == r) { return new MaxSubArray(a[l], a[l], a[l], a[l]); } int m = (l + r) >> 1; MaxSubArray lSubInfo = getInfo(a, l, m); MaxSubArray rSubInfo = getInfo(a, m + 1, r); return pushUp(lSubInfo, rSubInfo); } public static int maxSubArray(int[] nums) { return getInfo(nums, 0, nums.length - 1).mSum; } } ``` 上述代码定义了一个辅助类`MaxSubArray`用来存储四个重要参数:左端最大连续序列(`lSum`)、右端最大连续序列(`rSum`)、任意区间内的最大连续序列(`mSum`)及总(`iSum`)。函数`pushUp()`负责合并左右两半的信息形成整体信息对象。而核心逻辑由`getInfo()`递归调用完成,它会不断分割数组直至单个元素再逐步向上构建完整的答案结构。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值