53. Maximum Subarray - Easy

上周说要好好整理这道题的,因为确实花了很多时间去完成它。但是今天准备回顾的时候发现草稿纸一扔有很多细节记不起来了,看来还是要打铁趁热,现在我尽量写清楚自己的解题经过。

Description

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

Example:

Given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has the largest sum = 6, output the sum.

More practice:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

解题经过

思路

这道题要说是easy我认为是不太合适的,对着那个数组用眼睛扫一下,人脑似乎很容易判断哪个子串最大,但机器呢?遍历所有长度取值的可能子串吗,不用想了,肯定超时的。

最近学了分治的方法,这道题也是在leetcode上搜索分治出来的,所以分治有什么好的解决办法呢?我就一头扎下去往这方面想,怎样划分成规模更小的子问题,然后把他们的结果合并起来?

第一种想法

这是失败的尝试。我想的是,先把数组分成前后两半,分别找到两边的最大子串,然后再看二者是否能合并。这个想法并不容易实现,我遇到了很多的问题,比如怎样才算能合并——左边最大子串往右至右边最大子串往左这一段再算一次最大子串,而三个子串间隔的两段合并成两个负数(一定是负数,要么是空串),这五个值去作比较结果就比较明显了(写出来还是一套复杂的if else)。

总之,很难写,很多细节要想清楚和处理。我写第一版转成了链表结构,写了80多行嫌弃迭代器操作太多,然后第二版用vector下标操作舒服多了,然而写到最后的逻辑判断的时候也80多行了,却发现了一个重大漏洞,额,记不起来了。

第二种想法

这种时候已经非常受挫了,只是隐约觉得非要把整个数组割开来好像不太对,就换了一种。但这种做法仍然没有跳出一个死胡同:我的方法一直是基于合并,合并地越长越好。


合并的时候可以利用一些规律:

相邻的同号数字可以合并成更大/小的,于是整个数组可以变成连续的正负正负的形式;

头尾的负数肯定会被丢弃;

两个正数之间隔的负数绝对值如果同时小于两个整数,那么这两个整数就可以合并。


这样一趟趟去合并,每次也能把问题的规模减小,每次集中的处理三个相邻的数,这样也算是分治了。看一下我的主要递归代码:

53. Maximum Subarray - Easy_第1张图片

艰难地实现

一边写一边会发现很多细节问题,比如全为负数的情况要特殊处理,合并的过程判断的逻辑也要不断完善。最后是靠着那个长为1000的样例数组,不断测试和改bug出来的代码,最后有90行。.


53. Maximum Subarray - Easy_第2张图片
53. Maximum Subarray - Easy_第3张图片
53. Maximum Subarray - Easy_第4张图片

反思

1.我试着去分析自己算法的复杂度,发现不行,它太依赖于输入数组的排列情况。最好的一遍扫过就可以了,时间上还是不错的。

2.写出来太辛苦了,只当是一种锻炼吧。

3.写出来太辛苦了,下次不要钻牛角尖了,及时放弃做别的题比较好。要想思路开阔也要有个积累的过程。

借鉴

也看了别人的解法,最高票的解法据说是贪心算法的思想,以及看了另一个十几行的分治算法,都很巧妙。我也不知道吸收了多少东西,先这样吧哈哈。

你可能感兴趣的:(53. Maximum Subarray - Easy)