子数组最大累加和

53. 最大子数组和

 public int maxSubArray(int[] nums) {
        /**
        以当前索引结尾的情况下,最大的累加和
        由动态规划经过空间压缩后,用一个变量来更新记录
        有两种情况:
        1. pre<0的时候,当前数值nums[i]为最好情况
        2.pre>0时,pre+nums[i]
         */
        int ans=nums[0];
        for(int i=1,pre=nums[0];i<nums.length;i++){
            pre = Math.max(nums[i],pre+nums[i]);
            ans = Math.max(ans,pre);
        }
        return ans;

    }

198. 打家劫舍

 public int rob(int[] nums) {
        /**
        要保证最大金额,且不相邻,可以从是否考虑当前元素的角度
        则取决于nums[i],nums[i]+dp[i-2],nums[i]三种情况的最大值
        空间压缩,则需要两个变量进行动态更新
         */
        int n = nums.length;
        // 数组长度为1时
        if(n==1){
            return nums[0];
        }
        // 数组长度为2时
        if(n==2){
            return Math.max(nums[0],nums[1]);
        }
        int prePre=nums[0];
        int pre = Math.max(nums[0],nums[1]);
        for(int i =2,cur;i<n;i++){
            cur=Math.max(pre,Math.max(prePre+nums[i],nums[i]));
            prePre=pre;
            pre=cur;
        }
        return pre;
    }

918. 环形子数组的最大和

public int maxSubarraySumCircular(int[] nums) {
        /**
        有两种情况,1.连续,那就是求子数组的最大累加和
        2.不连续,位于数组的首尾部分,那就考虑用整个数组的和,减去中间连续的最小和
         */

        int all=nums[0], maxPre=nums[0], minPre=nums[0];
        int maxSum=nums[0], minSum=nums[0];
        for(int i =1;i<nums.length;i++){
            all+=nums[i];
            maxPre = Math.max(nums[i],nums[i]+maxPre);
            maxSum = Math.max(maxPre,maxSum);
            minPre = Math.min(nums[i],nums[i]+minPre);
            minSum = Math.min(minPre,minSum);
        }
        // 排除特殊情况,当数组总和等于最小和时,但要求不能返回空数组,那么就去maxSum,
        // 即所有小数中最大的
        return all==minSum ? maxSum : Math.max(maxSum,all-minSum);
    }

213. 打家劫舍Ⅱ

public int rob(int[] nums) {
        /**
        这里可以从是否考虑nums[0]的角度着手
        1.确定要nums[0],那么就是在[2...n-2]上进行不能选相邻元素的最大累加和
        2.不要nums[0],那么就是在[1...n-1]上进行不能选相邻元素的最大累加和操作
         */
        int n =nums.length;
        // 数组长度为1时
        if(n==1){
            return nums[0];
        }
        // 数组长度为2时
        if(n==2){
            return Math.max(nums[0],nums[1]);
        }
        return Math.max(f(nums,1,n-1),nums[0]+f(nums,2,n-2));
    }

    public static int f(int[] nums, int l, int r){
        // 当前范围无效
        if(l>r){
            return 0;
        }
        // 当前范围只要一个元素
        if(l==r){
            return nums[l];
        }
        // 当前范围只要两个元素
        if(l+1==r){
            return Math.max(nums[l],nums[r]);
        }
        int prePre = nums[l];
        int pre = Math.max(nums[l],nums[l+1]);
        for(int i=l+2, cur; i<=r;i++){
            cur = Math.max(pre,Math.max(prePre+nums[i],nums[i]));
            prePre=pre;
            pre=cur;
        }
        return pre;
    }

2560. 打家劫舍Ⅳ

public int minCapability(int[] nums, int k) {
        /**
         二分法+动态规划
         首先通过二分法来确定最小的窃取能力
         通过动态规划,在确定了最小能力的请款报告下,判断能偷几间房
         由于这里统计的是几间房,而不是收益金额,可以小贪心优化一下
         只要能投这个房间就偷,并且跳两下,保证不相邻
         否则跳一下
         */

        int n = nums.length,l=nums[0],r=nums[0];
        for(int i=1;i<n;i++){
            l=Math.min(l,nums[i]);
            r=Math.max(r,nums[i]);
        }
        int m,ans=0;
        while(l<=r){
            m=(l+r)/2;
            if(f(nums,n,m)>=k){
                ans=m;
                r=m-1;
            }else{
                l=m+1;
            }
        }
        return ans;
    }
    public int f(int[] nums, int n, int ability){
        int ans = 0;
        for(int i =0; i<n;i++){
            if(nums[i]<=ability){
                ans++;
                i++;
            }
        }
        return ans;
    }

面试题17.24. 最大子矩阵

public int[] getMaxMatrix(int[][] matrix) {
        /**
        时间复杂度为O(n^3)
        将二维数组转换成一维数组
         */
        int n=matrix.length;
        int m=matrix[0].length;
        int max = Integer.MIN_VALUE;
        int a=0,b=0,c=0,d=0;
        // 用一个一维数组来记录子矩阵的压缩值
        int[] nums = new int[m];
        for(int up=0;up<n;up++){
            // 每一轮(即压缩的开始行不同)时需要清空
            Arrays.fill(nums,0);
            for(int down = up;down<n;down++){
                // 接下来就是在一维子数组中找到最大的累加和
                for(int l=0,r=0,pre = Integer.MIN_VALUE;r<m;r++){
                    // 将up-down行的数据累加压缩到一维数组中
                    nums[r]+=matrix[down][r];
                    // 当一维数组中的pre大于0时,就累加
                    // 否则,更新为nums[r],并且开始的索引更新为当前r
                    if(pre>=0){
                        pre+=nums[r];
                    }else{
                        pre=nums[r];
                        l=r;
                    }
                    // 当找到更大的值时,更新max,并更新左上角和右下角的索引编号a,b,c,d
                    if(pre>max){
                        max=pre;
                        a=up;
                        b=l;
                        c=down;
                        d=r;
                    }
                }
            }
        }
        return new int[]{a,b,c,d};
    }

152. 乘积最大子数组

public int maxProduct(int[] nums) {
        /**
        对于当前元素有三种情况得到乘积最大
        1. 当前元素本身(前一个元素为小数时)
        2.当前元素与前一个最大乘积相乘
        2.当前元素与前一个最小乘积相乘(当前元素为负数时)
         */
        int ans =nums[0] ;
        for(int i=1, max=nums[0],min=nums[0],curMax,curMin;i<nums.length;i++){
            curMax=Math.max(nums[i],Math.max(nums[i]*max,nums[i]*min));
            curMin=Math.min(nums[i],Math.min(nums[i]*max,nums[i]*min));
            max=curMax;
            min=curMin;
            ans=Math.max(ans,max);
        }
        return ans;
    }

689. 三个无重叠子数组的最大和

public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        /**
        本题需要三个辅助参数
        1.sums[i]表示以i开头的k长度的累加和
        2.prefix[i]表示[0...i]范围上长度为k的子数组中最大sum的开头索引
        3.suffix[i]:表示[i...n-1]范围上长度为k的子数组和最大的开索引
        注意:> >=的地方
         */
        int n = nums.length;
        int[] sums = new int[n];
        for(int l=0,r=0,sum=0;r<n;r++){
            sum+=nums[r];
            if(r-l+1==k){
                sums[l]=sum;
                sum-=nums[l];
                l++;
            }
        }
        // prefix[i]
        int[] prefix=new int[n];
        for(int l=1,r=k;r<n;r++,l++){
            // 只能时> 保证字典序最小,相等也不更新
            if(sums[l]>sums[prefix[r-1]]){
                prefix[r]=l;
            }else{
                prefix[r]=prefix[r-1];
            }
            
        }
        // suffix[i]
        int[] suffix=new int[n];
        suffix[n-k]=n-k;
        for(int l=n-k-1;l>=0;l--){
            // 为了保证字典序最小,在相等时必须更新
            if(sums[l]>=sums[suffix[l+1]]){
                suffix[l]=l;
            }else{
                suffix[l]=suffix[l+1];
            }
        }
        int a=0,b=0,c=0,max=0;
        for(int p,s,i=k,j=2*k-1,sum;j<n-k;i++,j++){
            p=prefix[i-1];
            s=suffix[j+1];
            sum=sums[p]+sums[s]+sums[i];
            if(sum>max){
                max=sum;
                a=p;
                b=i;
                c=s;
            }
        }
        return new int[] {a,b,c};
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值