LeetCode 53最大子数组和

141 阅读2分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。

题目:给定一个整数数组nums,要求找出该整数数组中其中一个具有最大和的连续子数组,输出该最大和。

解题思路

本题的简单想法是一个个试,通过暴力解法得到所有子数组的和,返回其中最大的即可,代码只需两层for循环即可,代码如下:

public int maxSubArray(int[] nums) {
        int max = Integer.MIN_VALUE;
        for(int i=0;i<nums.length;i++){
            int temp=0;
            for(int j=i;j<nums.length;j++){
                temp += nums[j];
                max = Math.max(max, temp);
            }
        }
        return max;
    }

上述代码时间复杂度为O(N2)O(N^2),空间复杂度为O(1)O(1)。代码逻辑应该没问题,但在力扣超出时间限制,无法通过,看了一下没通过的测试数据,数据在这,够狠。。。小看着也有一万多了吧。

动态规划

利用动态规划首先需要找到动态规划的状态数组,假设记录的状态数组为dp,那么dp[i]记录的就是以第i个元素为结尾的连续子数组的最大和,dp[i]=max{dp[i-1]+nums[i], nums[i]},之后比较状态数组和最大值的大小即可得到最大子数组和,根据上述状态方程,可得下列代码:

public int maxSubArray(int[] nums) {
        int max=nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for(int i=1;i<nums.length;i++){
            dp[i] = Math.max(dp[i-1]+nums[i], nums[i]);
            max = Math.max(max, dp[i]);
        }
        return max;
    }

上述代码运行耗时2ms,时间复杂度为O(N)O(N),空间复杂度为O(N)O(N)。观察上述代码,可以发现我们每次只使用了状态方程的前一个状态值,而再之前的其他状态值则没有用到,此时我们可以简化代码,利用一个变量来保存前一个状态,不断更新此状态即可得到最终解,代码如下:

public int maxSubArray(int[] nums) {
        int pre=nums[0], max=nums[0];
        for(int i=1;i<nums.length;i++){
            pre = Math.max(pre+nums[i], nums[i]);
            max = Math.max(max, pre);
        }
        return max;
    }

上述代码最终耗时1ms,时间复杂度还是O(N)O(N),空间复杂度则变为O(1)O(1)

最后

本题还能用分治的方法来解决,方法类似二分排序,但感觉较为繁琐,动态规划是一个很好的方法,但目前对动态规划还不是很熟。。。只能新的一年加油吧~!