zoukankan      html  css  js  c++  java
  • 剑指Offer_#42_连续子数组的最大和

    剑指offer

    Contents

      • 题目
      • 思路分析
        • 方法1:暴力搜索
        • 方法2:分析规律得到启发式的算法
        • 方法3:动态规划
      • 解答
        • 解法1:暴力搜索
        • 解法2:观察规律
        • 解法3:动态规划

     

    题目

    输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
    要求时间复杂度为O(n)。

    示例1:

    输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

    提示:

    1 <= arr.length <= 10^5
    -100 <= arr[i] <= 100

     

    思路分析

     

    方法1:暴力搜索

    两层循环,遍历所有可能的连续子数组,比较得出他们当中最大的连续子数组和。时间超限。面试最好别这么写。

     

    方法2:分析规律得到启发式的算法

    可以从头到尾逐渐计算连续和,分析求最大连续和的过程,如下图。
    [图片]
    发现我们可以用两个变量来保存“累加的数组和”及“最大的数组和”两个数字,在遍历数组的过程中不断更新这两个变量。
    循环结束即可得到最大连续子数组和。

     

    方法3:动态规划

    • 状态定义:dp[i]是以nums[i]作为结尾的连续子数组的最大和。
    • 状态转移:
      • dp[i] = dp[i - 1] + nums[i] (dp[i - 1] > 0)
      • dp[i] = nums[i] (dp[i - 1] <= 0)

    其实这个思路跟方法2写出的代码一摸一样,只不过感觉这样分析更符合“套路”,更通用一些。

     

    解答

     

    解法1:暴力搜索

    class Solution {
        public int maxSubArray(int[] nums) {
            int max = nums[0];
            int sum = nums[0];
            for(int i = 0;i <= nums.length - 1;i++){
                //进入第二层循环之前,sum需要重置,因为这时开始算另一个连续子数组了
                sum = 0;
                for(int j = i; j <= nums.length - 1;j++){
                    //计算从nums[i]开始的所有连续和,作为最大值的候选
                    sum += nums[j];
                    max = Math.max(max, sum);//更新max
                }
            }
            return max;
        }
    }

    超出时间限制。

     

    解法2:观察规律

    class Solution {
        public int maxSubArray(int[] nums) {
            int tmpSum = nums[0];//保存当前的连续和(可能是最大连续和)
            int maxSum = nums[0];//保存结果
            for(int num:nums){
                //如果加上之前的连续还没有当前的num大,就可以抛弃前面的tmpSum了
                tmpSum = Math.max(tmpSum + num,num);
                maxSum = Math.max(tmpSum, maxSum);
            }
            return maxSum;
        }
    }

     

    解法3:动态规划

    class Solution {
        public int maxSubArray(int[] nums) {
            int res = nums[0];//存储结果
            int cur = nums[0];//存储dp[i]
            int pre = 0;//存储dp[i-1]
            for(int num:nums){
                //当dp[i-1] > 0:dp[i] = dp[i-1] + num
                //当dp[i-1] <= 0:dp[i] = num
                cur = num + Math.max(pre, 0);
                res = Math.max(res ,cur);
                //状态更新,本轮循环的cur,是下轮循环的cur
                pre = cur;
            }
            return res;
        }
    }
  • 相关阅读:
    记录 vue 中使用 SVG 渐变填充遇到过的坑
    关于map some filter every等遍历的一些临时记忆
    Blob文件处理
    电子签名 VUE加canvas实现 移动端和PC实现
    js导出excell表
    video
    移植QT5.6到嵌入式开发板(史上最详细的QT移植教程)
    Ubuntu16.04打开Qt显示/home/user/.config/QtProject/qtcreator/qtversion.xml : Permission denied
    哨兵2号影像数据获取以及处理流程
    Sentinel-2 哨兵二号数据下载及处理教程
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13308876.html
Copyright © 2011-2022 走看看