给定一个数组,求它的一个子数组,使其求和最大。

这个问题的应用:给定一只股票很多天的价格,计算从哪天买进哪天卖出能获得最大利润。

给定

prices:100   113   98   87   65   78   120   110   115

计算delta

delta:           13    -15  -11  -22   13    42    -10    5

求delta数组的最大连续子数组就能得到最大利润。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1231

解法1:Devide and Conquer

1)将delta按中点分为两个数组left[l...mid]、right[mid+1...r],最大子数组要么在left中,要么在right中,要么跨越left和right。

2)将其递归划分至原子问题,left中一个元素,right中一个元素。最大子数组要么是left[l],要么是right[r],要么是left[l]+right[r]。

3)先不考虑跨越left和right的情况,那么求left和right中的最大子数组,就是原问题的子问题,原问题时间复杂度T(n),该子问题复杂度为T(n/2)。

4)将求跨越left和right的最大子数组的问题额外处理。其最大值一定是  left中以mid为右端点的最大子数组  加上  right中以mid+1为左端点的最大子数组。求这个问题的时间复杂度可以做到O(n)。最终T(n)=2T(n/2)+O(n),整个问题的复杂度为O(nlogn)。

#include<iostream>
#include<cstdio>
using namespace std; #define N 10005 struct Pair {
int sum, left,right;
Pair() {}
explicit Pair(int s, int l, int r)
{
sum = s;
left = l;
right = r;
}
bool operator < (const Pair& p)const
{
return sum < p.sum;
}
bool operator <= (const Pair& p)const
{
return sum <= p.sum;
}
}; int n, num[N],preSum[N],sufSum[N]; Pair findMaxCrossSubarr(int l, int r)
{
int mid = (l + r) / ,lmax_l=mid,rmax_r=mid+,lmax=num[mid],rmax=num[mid+];
for (int i = l; i < mid; i++)
{
int tmp = preSum[mid] - preSum[i - ];
if (tmp > lmax)
{
lmax = tmp;
lmax_l = i;
}
}
for (int i = mid + ; i <= r; i++)
{
int tmp = sufSum[mid + ] - sufSum[i+];
if (tmp > rmax)
{
rmax = tmp;
rmax_r = i;
}
}
//cout << rmax + lmax << " " << lmax_l << " " << rmax_r << endl;
/*if(rmax+lmax<0)
return Pair(0, l, r);
else */
return Pair(rmax + lmax, lmax_l, rmax_r); } Pair findMaxSubarr(int l, int r)
{
if (l == r)
return Pair(num[l], l, r);
int mid = (l + r) / ;
Pair lpair = findMaxSubarr(l, mid);
Pair rpair = findMaxSubarr(mid + , r);
Pair xpair = findMaxCrossSubarr(l, r);
//cout << "*" << lpair.sum << " " << rpair.sum << " " << xpair.sum << endl;
if (rpair <= lpair&&xpair <= lpair)
return lpair;
else if (lpair < rpair&&xpair < rpair)
return rpair;
else
return xpair;
} int main()
{
while (scanf_s("%d", &n) != EOF && n)
{
for (int i = ; i <= n; i++)
{
scanf_s("%d", &num[i]);
preSum[i] = preSum[i - ] + num[i];
}
for (int i = n; i > ; i--)
sufSum[i] = sufSum[i + ] + num[i];
Pair res = findMaxSubarr(, n);
//printf("%d %d %d\n", res.sum, res.left, res.right);
if (res.sum < )
printf("0 %d %d\n", num[], num[n]);
else
printf("%d %d %d\n", res.sum, num[res.left], num[res.right]);
//cout << endl;
}
return ;
}

解法2:Dynamic Programming 线性时间复杂度

假如知道以r为右端点的最大子数组,将其扩展到以r+1为右端点的最大子数组,若dp[r]>=0,则dp[r+1]=dp[r]+num[r+1];若dp[r]<0,则dp[r+1]=num[r+1];

#include<iostream>
#include<cstdio>
using namespace std; #define N 10005 int main()
{
int n;
while (scanf_s("%d", &n) != EOF && n)
{
int num[N];
for (int i = ; i <= n; i++)
scanf_s("%d", &num[i]);
int dp = -, dp1 = , l = , r = , maxn = -, tl = , tr = ;
for (int i = ; i <= n; i++)
{
if (dp < )
{
dp = num[i];
tl = tr = i;
}
else
{
dp += num[i];
tr = i;
}
if (dp > maxn)
{
maxn = dp;
l = tl;
r = tr;
}
}
if(maxn<)
printf("0 %d %d\n", num[], num[n]);
else
printf("%d %d %d\n", maxn, num[l], num[r]);
}
return ;
}

Divide and Conquer_1.最大连续子数组的更多相关文章

  1. LeetCode 581. Shortest Unsorted Continuous Subarray (最短无序连续子数组)

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  2. [LeetCode] Shortest Unsorted Continuous Subarray 最短无序连续子数组

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  3. Java课程课后作业190315之从文档中读取随机数并得到最大连续子数组

    从我上一篇随笔中,我们可以得到最大连续子数组. 按照要求,我们需要从TXT文档中读取随机数,那在此之前,我们需要在程序中写入随机数 import java.io.File; import java.i ...

  4. Leetcode 581.最短无序连续子数组

    最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, ...

  5. LeetCode 581. 最短无序连续子数组(Shortest Unsorted Continuous Subarray)

    581. 最短无序连续子数组 581. Shortest Unsorted Continuous Subarray 题目描述 给定一个整型数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序 ...

  6. 【LeetCode】1438. 绝对差不超过限制的最长连续子数组 Longest Continuous Subarray With Absolute Diff Less Than or Equal t

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 日期 题目地址:https://leetco ...

  7. The Day Two 找到一个具有最大和的连续子数组,返回其最大和

    """ 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5, ...

  8. Leetcode581.Shortest Unsorted Continuous Subarray最短无序连续子数组

    给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, 6, 4, 8, 1 ...

  9. 力扣1438. 绝对差不超过限制的最长连续子数组-C语言实现-中等难度

    题目 传送门 文本 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条 ...

随机推荐

  1. mac下破解apk文件以及apktool的相关使用

    Android apktool是一个用来处理APK文件的工具,可以对APK进行反编译生成程序的源代码和图片.XML配置.语言资源等文件,也可以添加新的功能到APK文件中.用该工具来汉化Android软 ...

  2. mysql06---权限控制

    mysql权限管理: mysql的权限控制,首先在user表判断有没有权限连,连上后看有没有全局权限.然后看db表有哪些库级别的权限.然后看tables_priv表有哪些表级别的权限.最后还可以看有哪 ...

  3. YTU 2418: C语言习题 矩阵元素变换

    2418: C语言习题 矩阵元素变换 时间限制: 1 Sec  内存限制: 128 MB 提交: 293  解决: 155 题目描述 将一个n×n(2<n<10,n为奇数)的矩阵中最大的元 ...

  4. Mac下svn搭建和使用方法

    先安装svn服务器,然后执行以下步骤: 1.创建svn服务器库:svnadmin create ~/Documents/tools/svn/server/code 2.启动svn服务器:svnserv ...

  5. Ubuntu redmine 安装

    /******************************************************************** * Ubuntu redmine 安装 * 说明: * 随着 ...

  6. 【转】vue中的钩子函数。。

    前言 在vue开发SPA应用的过程中,多数情况下我们需要解决一个问题 就是在路由跳转的过程中需要更新你SPA应用的 title , 这一节不说其他,就展示如何使用 vue-router 的 导航钩子  ...

  7. AutoIT: 下载文件函数

    Func down() $Size=InetGetSize($a[$j][]);获得FTP上的文件的大小 InetGet($a[$j][],$a[$j][],,);下载 ProgressOn(],), ...

  8. 进击的Python【第十三章】:Web前端基础之HTML与CSS样式

    进击的Python[第十四章]:Web前端基础之HTML与CSS样式 一.web框架的本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客 ...

  9. LightOj 1220 Mysterious Bacteria

    题目大意: 给出一个x,求满足x = b^p,p最大是多少? 解题思路: x可以表示为:x = p1^e1 * p2^e2 * p3^e3 ....... * pn^en. p = gcd (e1,e ...

  10. Kuskal/Prim POJ 1789 Truck History

    题目传送门 题意:给出n个长度为7的字符串,一个字符串到另一个的距离为不同的字符数,问所有连通的最小代价是多少 分析:Kuskal/Prim: 先用并查集做,简单好写,然而效率并不高,稠密图应该用Pr ...