题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

LeetCode:53. 最大子序和

题解

显而易见的暴力解法

最容易想到的便是暴力穷举所有的子段和的开头,显而易见时间复杂度是O(n^2)。

代码:

class Solution {
public int maxSubArray(int[] nums) {
int maxSum = Integer.MIN_VALUE;
int n = nums.length;
for(int i = 0;i < n;i++){//穷举所有的开头
int thisSum = 0;
for(int j = i;j < n;j++){//穷举当前开头的子段和
thisSum += nums[j];
maxSum = Math.max(maxSum,thisSum);
}
}
return maxSum;
}
}

不是那么难的分治解法

本题也是分治解法应用的一个典型例子。“分”即将数组分为前后两段求解,“治”即分别求两段的最大子段和,“合”即比较两段的最大子段和和跨段的子段和,取最大值。

代码:

class Solution {
public int maxSubArray(int[] nums) {
return maxSub(nums, 0, nums.length - 1);
}
private int maxSub(int nums[], int left, int right){
if (left == right){
return nums[left];
}
int maxSum = 0;
int middle = (left + right) / 2;
int leftMaxSum = maxSub(nums, left, middle);//最半段最大子段和
int rightMaxSum = maxSub(nums, middle + 1, right);//右半段最大子段和
int leftRightSum = Integer.MIN_VALUE;//左半段以middle结尾的最大子段和
int rightLeftSum = Integer.MIN_VALUE;//右半段以middle+1开头的最大子段和
int thisLeftRightSum = 0;
int thisRightLeftSum = 0;
for(int j = middle;j >= left;j--){
thisLeftRightSum += nums[j];
leftRightSum = Math.max(leftRightSum,thisLeftRightSum);
}
for(int j = middle+1;j <= right;j++){
thisRightLeftSum += nums[j];
rightLeftSum = Math.max(rightLeftSum,thisRightLeftSum);
}
int crossMaxSum = leftRightSum + rightLeftSum;//跨段最大子段和
if(crossMaxSum>leftMaxSum&&crossMaxSum>rightMaxSum){
return crossMaxSum;
}else{
return Math.max(leftMaxSum,rightMaxSum);
}
}
}

时间复杂度分析:合的时间复杂度是O(n),分的时间复杂度是2*T(n/2)。

则\(T(n) = 2T(\frac{n}{2}) + O(n)\)。根据主定理, θ(f(n)) = θ(n) ,\(\log_b a = \log_2 2 = 1\),两者渐进复杂度相当,故时间复杂度为θ(nlogn)。

巧妙的动态规划

暴力解法穷举所有的开头,那么我们可不可以穷举所有的结尾?

对于数组中的任意一个元素,他要么是某个子段和的结尾,要么自己单独成为子段。因此后面的状态可以由前面的状态得出,可以使用动态规划。

代码:

class Solution {
public int maxSubArray(int[] nums) {
int maxSum = Integer.MIN_VALUE;
int thisSum = 0;
for(int i=0;i<nums.length;i++){
//如果已经求得的子段和加上当前元素比当前元素还小,说明前面求得的子段和没有意义
//那么子段和应更新为当前元素
thisSum = Math.max(nums[i],thisSum+nums[i]);
maxSum = Math.max(maxSum,thisSum);
}
return maxSum;
}
}

时间复杂度分析:只遍历一遍数组,时间复杂度为O(n),辅助空间为常数空间O(1)。

更加复杂的递归,线段树的隐用

最大子序和:暴力->递归->动规->线段树的更多相关文章

  1. 【递归】【线段树】【堆】AtCoder Regular Contest 080 E - Young Maids

    给你一个1~n的排列p,n是偶数,每次从中任选一对相邻的数出来,插到排列q的开头,如此循环,问你所能得到的字典序最小的排列q. 我们先确定q开头的两个数q1,q2,q1一定是p的奇数位的最小的数,而q ...

  2. ZKW线段树 非递归版本的线段树

    学习和参考 下面是支持区间修改和区间查询的zkw线段树模板,先记下来. #include <algorithm> #include <iterator> #include &l ...

  3. NOIP2013 提高组day2 2 花匠 动规 找拐点 树状数组

    花匠 描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致. 具体 ...

  4. hdu 3887 Counting Offspring(DFS序【非递归】+树状数组)

    题意: N个点形成一棵树.给出根结点P还有树结构的信息. 输出每个点的F[i].F[i]:以i为根的所有子结点中编号比i小的数的个数. 0<n<=10^5 思路: 方法一:直接DFS,进入 ...

  5. CF620E New Year Tree 线段树+dfs序+bitset

    线段树维护 dfs 序是显然的. 暴力建 60 个线段树太慢,于是用 bitset 优化就好了 ~ code: #include <bits/stdc++.h> #define M 63 ...

  6. cdoj 574 High-level ancients dfs序+线段树

    High-level ancients Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/s ...

  7. bzoj2819 DFS序 + LCA + 线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2819 题意:树上单点修改及区间异或和查询. 思维难度不高,但是题比较硬核. 整体思路是维护每一个结 ...

  8. Codeforces343D(SummerTrainingDay06-F dfs序+线段树)

    D. Water Tree time limit per test:4 seconds memory limit per test:256 megabytes input:standard input ...

  9. hdu5692【dfs序】【线段树】

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

随机推荐

  1. Linux_搭建NFS服务(基础)

    [RHEL8]-NFSserver :[Centos7]-NFSclient !!!测试环境我们首关闭防火墙和selinux(NFSserver和NFSclient都需要) [root@localho ...

  2. (全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系?

    (全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系? 产品经理马忠信关注 22015.08.30 13:59:20字数 2,660阅读 52,661 今天我给大家来讲讲这几个咱们经常打交道的词到 ...

  3. python基础之面向对象(一)(概念、实例、魔法方法)

    一.面向对象概念理解 1.面向对象和面向过程 面向过程:核心过程二字,过程即解决问题的步骤,就是先干什么后干什么 基于该思想写程序就好比在这是一条流水线,是一种机械式的思维方式 优点:复杂的过程流程化 ...

  4. EasyUI系列—点击按钮加载tabs_day26

    我们先来看下效果图 1.为div添加点击事件(也可使用jQuery绑定事件) 1 <div id="mm2" style="width:100px;"&g ...

  5. 使用goland调试远程代码

    前言 很多时候我们都在window上使用goland,并直接使用goland调试go代码. 但是很多时候我们的程序运行在Linux服务器上,虽然可以通过dlv命令行进行手动打断点调试,但是太麻烦了. ...

  6. Step By Step(Lua编译执行与错误)

    Step By Step(Lua编译执行与错误) 1. 编译:    Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块.但实际上dofile只是一个辅助函数,loadfile才 ...

  7. Docker学习(4) 守护式容器

    守护式容器 stop - 等待信号 kill - 直接干死

  8. TheSuperego 实验五 团队作业2:毕业设计选题系统

    项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST 这个作业要求链接 https://www.cnblogs.com/nwnu-dai ...

  9. nvJPEG库

    nvJPEG库 GPU加速的JPEG解码器,编码器和代码转换器 nvJPEG库是高性能的GPU加速库,用于解码,编码和转码JPEG格式的图像.nvJPEG2000库用于解码JPEG 2000格式的图像 ...

  10. 利用NVIDIA-NGC中的MATLAB容器加速语义分割

    利用NVIDIA-NGC中的MATLAB容器加速语义分割 Speeding Up Semantic Segmentation Using MATLAB Container from NVIDIA NG ...