【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】

在这里插入图片描述

算法题

算法刷题专栏 | 面试必备算法 | 面试高频算法
越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
作者简介:硕风和炜,CSDN-Java领域新星创作者,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享
恭喜你发现一枚宝藏博主,赶快收入囊中吧
人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?

算法题

在这里插入图片描述

目录

    • 题目链接
    • ⛲ 题目描述
    • 求解思路&实现代码&运行结果
      • ⚡ 暴力递归
        • 求解思路
        • 实现代码
        • 运行结果
      • ⚡ 记忆化搜索
        • 求解思路
        • 实现代码
        • 运行结果
      • ⚡ 动态规划
        • 求解思路
        • 实现代码
        • 运行结果
        • 代码优化
      • ⚡ 分治法
        • 求解思路
        • 实现代码
        • 运行结果
    • 共勉

题目链接

  • 53. 最大子数组和

⛲ 题目描述

给你一个整数数组 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

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

求解思路&实现代码&运行结果


⚡ 暴力递归

求解思路

  1. 整个问题过程的求解思路就是大的规模划分为小的规模,进行一个求解,也就是我们常说的重复子问题,我们可以想到通过递归来做。
  2. 因为我们求解的是子数组,所有求得答案的结果中最大和一定是数组中连续的元素求和而得到的。
  3. 该类型的题目我们考虑以某一个位置结尾的情况是什么的样结果,枚举小于 cur 的子数组选或不选,比如当前来到了cur位置,那么cur位置的结果可能来自有哪些情况组成呢?1. 就由当前的位置组成,当前位置就是最大的。 2. 还有可能是前一个位置最大连续子数组的和+当前位置的结果。
  4. 最终当前位置结尾的最大值就是情况1和情况2的最大值。
  5. 因为每一个位置都是可能作为结束位置的,所有我们通过迭代的方式去调用我们递归的函数,每次将结束的位置传入。找到所有情况的最大值。

实现代码

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

    // 当前位置结尾最大值
    public int process(int index,int[] nums){
        if(index<0) return 0;
        return Math.max(process(index-1,nums)+nums[index],nums[index]);
    }
}

运行结果

时间超限了,不要紧哦,我还有锦囊妙计!

【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】_第1张图片


⚡ 记忆化搜索

求解思路

  1. 根据我们递归的分析,在递归的过程中会产生重复的子过程,所以我们想到了加一个缓存表,也就是我们的记忆化搜索。

实现代码

class Solution {
    public int max = Integer.MIN_VALUE;
    public int[] dp;
    public int maxSubArray(int[] nums) {
        int n=nums.length;
        dp=new int[n];
        Arrays.fill(dp,-1);
        for (int i = 0; i < nums.length; i++) {
            max = Math.max(max, process(i,nums));
        }
        return max;
    }
    
    public int process(int index,int[] nums){
        if(index<0) return 0;
        if(dp[index]!=-1) return dp[index];
        return dp[index]=Math.max(process(index-1,nums)+nums[index],nums[index]);
    }
}

运行结果

【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】_第2张图片


⚡ 动态规划

求解思路

  1. 按照我们之前递归和记忆化搜索的思路,通过动态规划实现出来。

实现代码

class Solution {
    public int max = Integer.MIN_VALUE;
    public int[] dp;
    public int maxSubArray(int[] nums) {
        int n=nums.length;
        dp=new int[n];
        dp[0]=nums[0];
        max=dp[0];
        for (int index=1;index<n;index++) {
            dp[index]=Math.max(dp[index-1]+nums[index],nums[index]);
            max = Math.max(max, dp[index]);
        }
        return max;
    }
}

运行结果

【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】_第3张图片

代码优化

空间优化即可。

class Solution {
    public int max = Integer.MIN_VALUE;

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

结果展示
【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】_第4张图片


⚡ 分治法

求解思路

  1. 求解的核心思路就是分类讨论,具体的情况如下:
  • 子区间 [left, mid];
  • 子区间 [mid + 1, right];
  • 包含子区间 [mid , mid + 1] 的子区间,即 nums[mid] 与 nums[mid + 1] 一定会被选取。
  1. 我们检查是否还有遗漏的情况,确定没有,那最大值就在三种情况中的一种。
  2. 接下来我们就来具体的实现一下代码。

实现代码

public class Solution {

    public int maxSubArray(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }
        return process(nums, 0, n - 1);
    }

    public int process(int[] nums, int left, int right) {
        if (left == right) {
            return nums[left];
        }
        int mid = left + (right - left) / 2;
        int sum = 0;
        int leftSum = Integer.MIN_VALUE;
        for (int i = mid; i >= left; i--) {
            sum += nums[i];
            if (sum > leftSum) {
                leftSum = sum;
            }
        }
        sum = 0;
        int rightSum = Integer.MIN_VALUE;
        for (int i = mid + 1; i <= right; i++) {
            sum += nums[i];
            if (sum > rightSum) {
                rightSum = sum;
            }
        }
        return Math.max(process(nums, left, mid), Math.max(process(nums, mid + 1, right), leftSum+rightSum));
    }
}

运行结果

【LeetCode: 53. 最大子数组和 | 暴力递归=>记忆化搜索=>动态规划 | 分治法 】_第5张图片

共勉

最后,我想和大家分享一句一直激励我的座右铭,希望可以与大家共勉!

在这里插入图片描述

你可能感兴趣的:(#,递归/回溯系列,#,动态规划系列,LeetCode每日一题打卡,leetcode,动态规划,java,算法,面试)