《程序员面试金典(第6版)》面试题 16.17. 连续数列(贪心算法思想,动态规划算法思想,C++)

题目描述

给定一个整数数组,找出总和最大的连续数列,并返回总和。

示例:

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

进阶:

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

解题思路与代码

  • 首先,这道题是一道稍微有点难度的简单题。需要同学们对贪心算法思想与动态规划算法思想有一点基础的了解。做这道题就会非常的简单。

  • 反之,可能会有点难。有可能你做出这道题后,你都不知道你使用的方法是贪心还是动态规划。

这道题题目的进阶说是可以使用分治算法去求解。我看了看,感觉实在是没有必要。因为,这只是道简单题。动态规划和贪心已经可以了。而分治呢,有一种舍近求远的感觉,还把这道题上升到了另一个高度。复杂度也比这两种的实现要高。所以,我真心觉得没有必要。所以也就不去做这个实现了。

方法一:贪心算法思想

  • 我做这道题的时候,我先是假定这道题里面的数组里面的数字,是有正有负的一个序列。
    • 那么我写的这个实现,前半部分就是试图在整个数组中,找到总和最大的连续数列,并返回总和。我用一个for循环与两个变量去实现这个算法。
    • 在遍历数组过程中,每次都选择使得当前连续子数组和 count 大于零的元素。当遇到使得 count 之和小于零的元素时,就选择跳过这个元素,重新开始累加。
  • 后来发现,这道题中,竟然有全都是负数的情况,那全都是负数我该怎么办呢?那当然是返回最小的那个负数了。
  • 最后返回结果即可

具体代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int count = 0;
        int result = 0;
        for(int i = 0; i < nums.size(); ++i){
            if(count + nums[i] < 0) {
                count = 0;
                continue;
            }
            count += nums[i];
            result = max(count,result);
        }
        if(result == 0){
            result = nums[0];
            for(int i = 1; i < nums.size(); ++i)
                result = max(result,nums[i]);
        }
        return result;
    }
};

在这里插入图片描述

复杂度分析
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

方法二:优化:动态规划思想

  • 相比与上一种的贪心算法思想,我觉得我这一种动态规划思想会使代码看的更有简介,并且效率更高。因为我优化掉了一个for循环。
  • 这个算法的思路是,从数组的第二个元素开始遍历,每次更新 currNum 为当前元素与 currNum 加上当前元素的较大值。
  • 这样一来,我们可以确保 currNum 始终是一个可能的连续子数组的和。
  • 然后我们将 maxNum 更新为 currNum 和 maxNum 中的较大值,这样我们就可以在遍历过程中找到最大的连续子数组和。

具体代码如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int currNum = nums[0]; 
        int maxNum = nums[0];
        for(int i = 1; i < nums.size(); ++i){
            currNum = max(nums[i],currNum + nums[i]);
            maxNum = max(currNum,maxNum);
        }
        return maxNum;
    }
};

在这里插入图片描述

复杂度分析
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

总结

这道题目(求最大连续子数组和)的意义在于:

  • 算法设计思路:这道题目提供了一个平台,让我们可以学习和探讨不同的算法设计思路,例如贪心算法、动态规划和分治法。通过比较和分析这些方法的优缺点,我们可以更好地理解这些算法设计思路及其应用场景。

  • 问题求解能力:解决这类问题可以锻炼我们的问题分析和解决能力。通过思考问题,我们学会将问题拆解成更小的子问题,然后寻找合适的方法将这些子问题的解合并成原问题的解。这种能力在实际编程工作中非常重要。

  • 代码实现技巧:编写不同解法的代码可以提高我们的编程技巧。例如,在实现动态规划解法时,我们需要考虑状态的表示和状态转移方程;在实现分治法时,我们需要掌握递归的技巧以及如何合并子问题的解。这些技巧都是编程过程中必备的能力。

  • 优化性能:这道题目也强调了优化算法性能的重要性。在实际应用中,我们往往需要在有限的时间和空间资源下求解问题。通过对比不同算法的时间复杂度和空间复杂度,我们可以更好地了解如何在实际问题中选择合适的算法。

总之,这道题目具有一定的教育意义和实际应用价值。通过学习和掌握这类问题的解决方法,我们可以提高自己的算法设计、问题求解和编程能力。

最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿宋同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值