前言

就有要把leetcode的题刷完,每天一道题,每天进步一点点


从零打卡leetcode之day 3

题目描述:
给定一个int类型的数组,求最大子序列的和。
也就是说,从这个数组中截取一个子数组,这个子数组的元素和最大。 例如:
-1 20 -4 14 -4 -2
这个数组的最大字序列和为30。即20 -4 14。

解题

1.初级版解法

对于这道题,其实我们可以采取遍历所有可能的组合,然后再比较哪种组合的和最大。

也就是说,我们可以找出所有子序列,然后逐个比较。代码如下。

    public int solve(int[] arrs){

        int max = 0;//用来存放目标子序列的和

        int temp = 0;//用来存每个子序列的和

        for(int i = 0; i < arrs.length; i++){

            for(int j = i; j < arrs.length; j++){

                temp = 0;

                //计算子序列的和
for(int k = 0; k < arrs.length; k++){
temp += arrs[k];
}
//进行比较
if(temp > max){
max = temp;
} }
} return max;
}`

在这三个循环中,外面两个循环枚举出所有子序列,第三个循环计算子序列的和。

看到三个for循环,时间复杂度的O(n3)。这速度,实在是太慢了。我们来优化优化。

2.进阶版

其实,你仔细看一下里面的那两层for循环,会发现其实可以把它们合并成一个for循环的。

也就是说,我们可以在枚举所有子序列的过程中,是可以一边进行数据处理的。还是直接看代码好理解点。如下:

    public int solve2(int[] arrs){

        int max = 0; 

        int temp = 0;

        for(int i = 0; i < arrs.length; i++){

            temp = 0;

            for(int j = i; j < arrs.length; j++){

                //一边处理数据
temp += arrs[j]; //进行比较选择 if(max < temp){ max = temp;
}
}
} return temp;
}

该方法用了两个for循环,时间复杂度为O(n2),相对来说好了一点。

3.再次优化进阶

这次,我们可以使用递归的思想来处理。递归最重要的就是要找到:

  1. 递归的结束条件
  2. 把问题分解成若干个子问题。

对于这道题,其实我们可以把序列分成左右两部分。那么,最大子序列和的位置会出现在以下三种情况:

  1. 子序列完全在左半部分。
  2. 子序列完全在右半部分。
  3. 一部分在左,一部分在右。

所以我们只要分别求出左半部分的最大子序列和、右半部分的最大子序列和(注意,问题已经转化为求左右两部分的最大子序列和了,也就是说问题被分解成若干子问题了)、以及跨越左右两部分的最大子序列和。最后比较三者之中哪个比较大就可以了。

如何求解左半部分和右半部分的最大子序列?

其实道理一样,把左半部分和右半部分再次分解左右两部分就可以了。

那么,如何求解跨越左右两部分的最大子序列呢?

其实只要求出包含左半部分中最右边元素的子序列的最大和,以及求出包含右半部分中最左边元素的子序列的最大和,然后让两者相加,即可求出跨域左右两部分的最大子序列和了。

子问题已经分解出来了,那么递归的结束条件是什么?

我们把数组分成左右两部分,其实当左右两部分只有一个元素时,递归结束。

这道题的递归思路算是找出来了,不过,代码实现?假如你对递归不大熟悉的话,可能在实现上还是有那么点困难的。对于递归的学习,大家也可以看我写的关于递归与动态规划的几篇文章。

我就直接抛代码了。

    //递归版本
public int solve3(int[] arrs, int left, int right){
int max = 0; //表示只有一个元素,无需在分解
if(left == right){
//为什么?因为低于0的数肯定不可以是最大值的
//大不了最大值为0
max = arrs[left] >= 0 ? arrs[left]:0;
}else{ int center = (left + right)/2;
//求解左半部分最大子序列
int leftMax = solve3(arrs, left, center);
//求解右半部分最大子序列
int rightMax = solve3(arrs, center+1, right); //求解kua跨越左右两部分的最大子序列
//1.求包含左部分最右元素的最大和
int l = 0;
int l_max = 0;
for(int i = center; i >= left; i--){
l += arrs[i];
if(l > l_max){
l_max = l;
}
} //2.求包含右部分最左元素的最大和
int r = 0;
int r_max = 0;
for(int i = center+1; i <= right; i++){
r += arrs[i];
if(r > r_max){
r_max = r;
}
}
//跨越左右两部分的最大子序列
max = l_max + r_max; //取三者最大值
if(max < leftMax) max = leftMax;
if(max < rightMax) max = rightMax;
} return max;
}

递归求解方法的时间复杂度为O(nlgn)。这速度,比第一种做法,不知道快了几个级别….

递归解法可以说是很快的了

但是,等等,我还是不满意…

4.最终版:动态规划

接下来的最终版,时间复杂度可以缩减到O(n), 虽然说是采用了动态规划的思想,不过,我觉得你没学过动态规划也可以看懂。

假如我给你

1 2 -4 5 6

五个元素,你在计算前面三个元素的时候,即

1 + 2 + -4 = -1

发现前面三个元素的和是小于0的,那么,这个

1 2 -4

的子序列我们还要吗?显然,这个子序列的和都小于0了,我们是可以直接淘汰的。因为如果还要这个子序列的话,它和后面的5一相加,结果变成了4,我们还不如让我们的目标子序列直接从5开始呢。

先看代码吧,可能反而会好理解点

    //基于动态规划的思想
public int solve4(int[] arrs){
int max = 0;//存放目标子序列的最大值
int temp = 0;//存放子序列的最大值 for(int i = 0; i < arrs.length; i++){
temp += arrs[i];
if(temp > max){
max = temp;
}else{
//如果这个子序列的值小于0,那么淘汰
//从后面的子序列开始算起
if(temp < 0){
temp = 0;
}
}
}
return max;
}

这道题不是leetcode上的题目,不过我觉得这道题很不错,所以拿出来分享给大家。

对付的对手

从0打卡leetcode之day 3 -- 最大子序列和的更多相关文章

  1. 从0打卡leetcode之day 6--最长回文串

    题目描述 给定一个字符串 s,找到 s中最长的回文子串.你可以假设 s 的最大长度为1000. 示例1 输入: "babad" 输出: "bab" 注意: &q ...

  2. 从0打卡leetcode之day 5 ---两个排序数组的中位数

    前言 我靠,才坚持了四天,就差点不想坚持了.不行啊,我得把leetcode上的题给刷完,不然怕是不好进入bat的大门. 题目描述 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . ...

  3. 从零打卡leetcode之day 2---两数相加

    前言 就是要把leetcode刷完,每天一道题,每天进步一点点. 从零打卡leetcode之day 2 题目描述: 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储, 它们的每个节点只存储单个 ...

  4. 从零打卡leetcode之day 1--两数之和

    前言 就是要把leetcode的题刷完,每天一道题,每天进步一点点 从零打卡leetcode之day 1 题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只 ...

  5. [LeetCode] Distinct Subsequences 不同的子序列

    Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequence ...

  6. LeetCode:递增的三元子序列【334】

    LeetCode:递增的三元子序列[334] 题目描述 给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列. 数学表达式如下: 如果存在这样的 i, j, k,  且满足 0 ≤ i ...

  7. LeetCode Maximum Product Subarray 最大子序列积

    题意:给一个size大于0的序列,求最大的连续子序列之积.(有正数,负数,0) 思路:正确分析这三种数.0把不同的可能为答案的子序列给隔开了,所以其实可以以0为分隔线将他们拆成多个序列来进行求积,这样 ...

  8. LeetCode 1143 最长公共子序列

    链接:https://leetcode-cn.com/problems/longest-common-subsequence 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序 ...

  9. 〖Android〗Nexus 7 flo (razor) 刷入Recovery/CM-11.0后卡在开机动画的解决方法

    操作日志: 起因:Nexus 7 flo 华硕平板,刷了一个CWM Recovery之后变成了砖机: 尝试1:使用CWM Recovery清除数据,开机失败 尝试2:刷入CM 11 Snapshot的 ...

随机推荐

  1. RF无线射频电路设计干货分享

    1.概述:射频(RF)PCB设计,在目前公开出版的理论上具有很多不确定性,常被形容为一种“黑色艺术”.通常情况下,对于微波以下频段的电路(包括低频和低频数字电路),在全面掌握各类设计原则前提下的仔细规 ...

  2. C# 串口操作系列(5)--通讯库雏形

    C# 串口操作系列(5)--通讯库雏形 标签: 通讯c#数据分析byteclassstring 2010-08-09 00:07 21378人阅读 评论(73) 收藏 举报  分类: 通讯类库设计(4 ...

  3. KindEditor富文本编辑器, 从客户端中检测到有潜在危险的 Request.Form 值

    在用富文本编辑器时经常会遇到的问题是asp.net报的”检测到有潜在危险的 Request.Form 值“一般的解法是在aspx页面   page  标签中加上 validaterequest='fa ...

  4. vue table-tree 组件

    最近接到一个需要使用table-tree开发 百度的一圈.什么的都有.感觉不怎么靠谱.最后找到一个感觉挺 huo shi 先附上demo和代码地址: 代码地址:https://github.com/s ...

  5. H5_ 多媒体video,autio使用示例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Hadoop集群搭建过程中ssh免密码登录(二)

    一.为什么设置ssh免密码登录 在集群中,Hadoop控制脚本依赖SSH来执行针对整个集群的操作.例如,某个脚本能够终止并重启集群中的所有守护进程.所以,需要安装SSH,但是,SSH远程登陆的时候,需 ...

  7. 28 ArcMap 运行特别慢怎么办

    小编电脑配置如下: , 虽然不是太好吧,但还是满足ArcMap运行的要求的,但不知道为什么,就是很慢,终于在无意中,发现了一个位置,取消勾选以后,ArcMap变的快很多,亲测有效 取消后台处理后,Ar ...

  8. Ubunto使用 码云 创建项目

    1.安装 git sudo apt-get install git配置 git 文件 git config --global user.name "你的用户名" git confi ...

  9. 关于using namespace std

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~关于using   namespace   std ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ...

  10. dijkstra算法解决单源最短路问题

    简介 最近这段时间刚好做了最短路问题的算法报告,因此对dijkstra算法也有了更深的理解,下面和大家分享一下我的学习过程. 前言 呃呃呃,听起来也没那么难,其实,真的没那么难,只要弄清楚思路就很容易 ...