• leetcode53 -- 最大数组和


    一、问题描述

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    子数组 是数组中的一个连续部分。

    示例 1:

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

    示例 2:

    输入:nums = [1]
    输出:1

    示例 3:

    输入:nums = [5,4,-1,7,8]
    输出:23

    提示:

    1 <= nums.length <= 105
    -104 <= nums[i] <= 104

    二、解决问题

    法一:贪心法

    思路:
    如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字。
    如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字(重新找新的子序列,将原来的序列抛弃)。

    class Solution {
        public int maxSubArray(int[] nums) {
            int sum = nums[0];
            int max = sum;
    
            for(int i = 1; i < nums.length; i++){
                if(sum > 0)
                    sum = sum + nums[i];
                else
                    sum = nums[i];
    
                if(sum > max)
                    max = sum;
            }
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    贪心法变种
    随便翻评论,看到了这么几行代码,真的是惊艳到我了,如下:

    #python
    class Solution(object):
        def maxSubArray(self, nums):
            for i in range(1,len(nums)):
                nums[i] = nums[i] + max(nums[i-1],0);
            return max(nums);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    大佬直接用初始的数组,存放之前连续子序列的最大值,不用在申请专门的变量来存储,再作比较,代码也很简洁,博主就像能不能用java也来实现以下,代码如下:

    //java
    class Solution {
        public int maxSubArray(int[] nums) {
            int max = nums[0];
            for(int i = 1; i < nums.length; i++){
                nums[i] = nums[i] + Math.max(nums[i-1], 0);
    
                if(nums[i] > max)
                    max = nums[i];
            }
    
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    法二:动态规划法

    思路:先遍历出 以某个节点为结束节点的所有子序列
    在这里插入图片描述

    • 其中 dp[ i ] (sum)记录的是以 nums[ i ] 为子序列末端的最大序子列连续和
    • 因为只需要知道dp的前一项,我们用sum代替一维数组
    • 该算法用到了“最佳子结构”(以每个位置为终点的最大子数列都是基于其前一位置的最大子数列计算得出)
    • 如果给的数全是负数的话,相当于找最大值
    • 这里的动态规划和贪心的代码其实是完全一致的,只是这行不等式左右移项之后得到了不同的式子(nums[i] < nums[i] + sum(动态规划) => sum > 0 (贪心))
    //java
    class Solution {
        public int maxSubArray(int[] nums) {
            int sum = nums[0];
            int max = sum;
    
            for(int i = 1 ;i < nums.length; i++){
                if(nums[i] < nums[i] + sum)
                    sum = nums[i] + sum;
                else
                    sum = nums[i];                
                
                if(max < sum)
                    max = sum;  
            }
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    #python
    class Solution:
        def maxSubArray(self, nums: List[int]) -> int:
            if not nums:
                return -2147483648;
                
            sum1 = nums[0];
            max1 = sum1;
    
            for i in range(1, len(nums)):
                sum1 = max(nums[i], sum1 + nums[i]);
                max1 = max(sum1, max1);
            return max1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 时间复杂度:O(n)
    • 空间复杂度:O(1)

    法三:暴力破解法

    class Solution {
        public int maxSubArray(int[] nums) {
            int max = nums[0];
            for(int i = 0; i < nums.length; i++){
                int sum = 0;
                for(int j = i; j < nums.length; j++){
                   sum = sum + nums[j];
                   if(sum > max)
                        max = sum; 
                }
                
            }
            return max;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 时间复杂度:O(n^2)
    • 空间复杂度:O(1)

    法四:分治法

    class Solution
    {
    public:
        int maxSubArray(vector<int> &nums)
        {
            //类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
            int result = INT_MIN;
            int numsSize = int(nums.size());
            result = maxSubArrayHelper(nums, 0, numsSize - 1);
            return result;
        }
    
        int maxSubArrayHelper(vector<int> &nums, int left, int right)
        {
            if (left == right)
            {
                return nums[left];
            }
            int mid = (left + right) / 2;
            int leftSum = maxSubArrayHelper(nums, left, mid);
            //注意这里应是mid + 1,否则left + 1 = right时,会无线循环
            int rightSum = maxSubArrayHelper(nums, mid + 1, right);
            int midSum = findMaxCrossingSubarray(nums, left, mid, right);
            int result = max(leftSum, rightSum);
            result = max(result, midSum);
            return result;
        }
    
        int findMaxCrossingSubarray(vector<int> &nums, int left, int mid, int right)
        {
            int leftSum = INT_MIN;
            int sum = 0;
            for (int i = mid; i >= left; i--)
            {
                sum += nums[i];
                leftSum = max(leftSum, sum);
            }
    
            int rightSum = INT_MIN;
            sum = 0;
            //注意这里i = mid + 1,避免重复用到nums[i]
            for (int i = mid + 1; i <= right; i++)
            {
                sum += nums[i];
                rightSum = max(rightSum, sum);
            }
            return (leftSum + rightSum);
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 时间复杂度:O(nlog(n))
    • 空间复杂度:O(log(n))

    参考:
    https://leetcode.cn/problems/maximum-subarray/solution/

  • 相关阅读:
    H3C无线控制器AP license共享配置
    基于JSP实现校园二手交易平台
    前端设计模式之【中介模式】
    单目3D自动标注
    提升组件库通用能力 - NutUI 在线主题定制功能探索
    ​Linux·i2c驱动架构​
    Deepin
    记录 | 修改docker存储路径
    基于JAVA小福星宠物领养演示视频计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    掌握这四步,月收入1万+的自媒体人可能就是你
  • 原文地址:https://blog.csdn.net/qq_39671159/article/details/125878040