最大子数组和最大值平均子数组
来源:互联网 发布:淘宝代销流程 编辑:程序博客网 时间:2024/05/20 09:08
1.最大子数组
给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
样例给出数组[−2,2,−3,4,−1,2,1,−5,3]
,符合要求的子数组为[4,−1,2,1]
,其最大和为6
法1:贪心
int maxSubArray(vector<int> nums) { // write your code here int sum=nums[0]; int t=sum; for(int i=1;i<nums.size();i++) { if(t<0)t=0; t=t+nums[i]; if(t>sum)sum=t; } return sum; }
法2:分治
class Solution {public: /** * @param nums: A list of integers * @return: A integer indicate the sum of max subarray */ int maxSubArray(vector<int> nums) { // write your code here return m(nums,0,nums.size()-1); } int cross(vector<int>nums,int start,int mid,int end) { int leftmax=0; int sum=INT_MIN; for(int i=mid;i>=start;i--) { leftmax+=nums[i]; if(sum<=leftmax)sum=leftmax; } leftmax=sum; int rightmax=0; sum=INT_MIN; for(int i=mid+1;i<=end;i++) { rightmax+=nums[i]; if(sum<=rightmax)sum=rightmax; } sum+=leftmax; return sum; } int m(vector<int>nums,int start,int end) { if(start==end)return nums[start]; int mid=(start+end)/2; int leftmax=m(nums,start,mid); int rightmax=m(nums,mid+1,end); int middlemax=cross(nums,start,mid,end); if(leftmax>=rightmax&&leftmax>=middlemax)return leftmax; else if(middlemax>=rightmax&&middlemax>=leftmax)return middlemax; else return rightmax; }};
法三:暴力(略)
2.最大平均子数组
给出一个整数数组,有正有负。找到这样一个子数组,他的长度大于等于 k
,且平均值最大。
给出 nums = [1, 12, -5, -6, 50, 3]
, k = 3
返回 15.667
// (-6 + 50 + 3) / 3 = 15.667
引用他人的思路
1、一个数组的子数组的最大平均数一定在数组的最大值和最小值之间,所以二分法的第一步限定average位于[min,max]之中。
2、接下去要做的就是不断的缩小范围,直至max-min足够小(如1e-6),那我们就得到了想要的结果。
缩小范围的思想如下:
每一轮设置mid=(min+max)/2,然后将原数组中的每一个数减去这个mid,如果能找到(经过提醒,改正为:大于等于)k个相邻数的总和大于0的情况,那么说明最终结果一定比这个mid要更大,限定下一轮寻找范围在[mid,max]之中。反之在限定在[min,mid]之中。
那么在实际算法中我们需要解决的关键一步就是,如何判断“有(大于等于)k个相邻数的总和大于0的情况存在”。
首先,我们可以用sum数组来存储减掉mid值的原数组的各总和(sum[i]存储num[0]-mid到num[i-1]-mid的总和),当sum[i]存储的总和个数超过k时(即i>k),也就是说我们保证了这个子数组的长度达到k后,可以砍掉之前一些拖后腿的数。这些拖后腿的数在上述链接的代码中是用min_pre来实现的。当之前拖后腿的数值小于min_pre时,更新min_pre=sum[i - k + 1]。sum[i]存储的是num[0]~num[i-1]减去mid的总和,而min_pre存储的是num[0]~num[k]减掉mid的总和,这样sum[i]-min_pre得到的是sum[k+1]~sum[i-1],它所记录的总和个数也就是到num[i]为止能够找到的最大平均数 子数组的长度。
代码:
class Solution {public: /** * @param nums an array with positive and negative numbers * @param k an integer * @return the maximum average */ double maxAverage(vector<int>& nums, int k) { // Write your code here double start=INT_MAX; double end=INT_MIN; for(int i=0;i<nums.size();i++) { if(nums[i]<=start)start=nums[i]; if(nums[i]>=end)end=nums[i]; } int len=nums.size(); double sum[len+1]; memset(sum,0,sizeof(sum)); while(end-start>1e-6) { double mid=(start+end)/2; double min_pre=0; bool flag=false; for(int i=1;i<=nums.size();i++) { sum[i]=sum[i-1]+nums[i-1]-mid; if(i>=k&&sum[i]-min_pre>=0) { flag=true; break;//只要有一组满足平均值大于mid就可以跳出内循环 } if(i>=k) { min_pre=min(min_pre,sum[i-k+1]); } } if(flag)start=mid; else end=mid; } return start; }};
3.通过做第二道题我又发现了一个做第一道题的方法
int maxSubArray(vector<int> nums) { // write your code here int sum[nums.size()+1]={0}; int min_pre=0; int maxn=INT_MIN; for(int i=1;i<=nums.size();i++) { sum[i]=sum[i-1]+nums[i-1]; if(sum[i]-min_pre>=maxn)maxn=sum[i]-min_pre; min_pre=min(sum[i],min_pre); } return maxn;}但仔细一想 其实这种方法就是用sum数列的最大值减去sum数列的最小值,第二题也是如此,就是用当前值减去最小值,在遍历的过程中更新最小值,最终得到正确的答案
- 最大子数组和最大值平均子数组
- 子数组和最大值
- 子数组和最大
- 最大子数组和
- 最大子数组和
- 子数组最大和
- 最大子数组和
- 子数组最大和
- 子数组最大和
- 最大子数组和
- 最大子数组和
- 子数组最大和
- 子数组最大和
- 最大子数组和
- 最大子数组和
- 最大子数组和
- 最大子数组和
- 最大子数组和
- linux系统下mongodb添加账号密码
- CodeForces 812A Sagheer and Crossroads
- OpenGL-2D(Cohen-Sutherland 裁线算法)
- iOS自带实现高斯模糊效果
- PHP入门之编写html页面的常用标签
- 最大子数组和最大值平均子数组
- 设计模式 建造者模式 Builder
- freemaker中小数展示为整数的问题
- 算法竞赛入门经典-习题3-4 周期串(Periodic Strings, UVa455)
- 水平居中布局解决方案
- Codeforces Round #417 (Div. 2) A. Sagheer and Crossroads
- ORA-00018 问题处理
- Guide to Elliptic Curve Cryptography (ECC椭圆曲线算法1)
- vs2015编辑器坏了输入\显示成¥