序言
昨天验收完实验很晚了,也发生了点不愉快的事故而推迟了,今天继续忙无休止的实验=。=
题目
熟悉的题目,记得当初实现想了半天,其实现在想来也是简单了的,从头搜索,找到加到目前的最大值,如果加到当前还是负数,那就干脆不要,归零继续,找个数记录其中的最大值即可
第一次实现
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int i, sum=0, max=0;
for(i=0;i<nums.size()-1;i++){
sum+=nums[i];
if(sum<0)
sum=0;
if(sum>max)
max=sum;
}
return max;
}
};
特地把这个小错误拿出来,虽然总体没错,但是还是需要警醒,为啥不一开始就考虑特殊情况?
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==0)
return 0;
if(nums.size()==1){
return nums[0];
}
int i, sum=nums[0], max=0;
int flag=0;
for(i=0;i<nums.size();i++){
if(nums[i]>0)
flag=1;
if(nums[i]>sum)
sum=nums[i];
}
if(flag==0)
return sum;
for(sum=0,i=0;i<nums.size();i++){
sum+=nums[i];
if(sum>max)
max=sum;
if(sum<0)
sum=0;
}
return max;
}
};
考虑特殊情况。。终于通过
然后就是试着用分治法实现了:
我其实并没有想通分治的可行性,网上学习一下吧,,
感谢大佬(https://blog.csdn.net/u014235934/article/details/51996493 )
分治法
分治法采用了递归的结构,将原问题分成几个规模较小但是类似于原问题的子问题, 通过递归的方式再来求解这些小问题,然后将子问题的解合并来建立原问题的解,分治法在每成递归时都有三个步骤:
分解: 将原问题分解成若干个小问题,这些子问题是原问题的规模较小的实例
解决: 解决这些子问题,通过递归的方式求解子问题,直到自问题的规模足够小,可以直接求解
合并: 将这些子问题的解合并成原问题的解
最大子序列和问题
比如说有一个数组:
4 , -3, 5, -2, -1, -1, 2, 6, -2
对于这样一个数组,它的最大子序列和为11(从第一个元素到第七个)。
对于任意一个栗子,可以发现最大子序列和只有三种情况:
出现在数组的左半部分
出现在数组的右半部分
出现在数组的中间部分,横跨左右两部分
(这不是废话么=_=)
而且对于左半部分或者右半部分,上述结论也成立,利用这特性,可以写出相应的递归,递归结束的条件是当只有一个元素时,判断这个元素是否大于零,大于零便返回这个数,否则返回零。
然后求出左边最大值,右边最大值和横跨两边的最大值,返回这三个值中的最大值
c语言代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 20
int max3(int, int, int);
int maxSubArrayAns(int []);
int maxSubArray(int [], int, int);
int main(){
int nums[MAX_N];
int i;
srand(time(0));
printf("array: \n");
for(int i = 0; i < MAX_N; i++){
nums[i] = (int)(rand() % (MAX_N * 2) - MAX_N);
printf("%d\t", nums[i]);
}
printf("\n");
printf("The max subsequen sum is %d.\n", maxSubArrayAns(nums));
return 0;
}
int max3(int a, int b, int c){
if(a > b)
return a > c ? a : c;
else
return b > c ? b : c;
}
int maxSubArray(int nums[], int left, int right){
int maxLeftSum, maxRightSum;
int maxLeftBorderSum, maxRightBorderSum;
int leftBorderSum, rightBorderSum;
if(left == right)
if(nums[left] > 0)
return nums[left];
else
return 0;
int mid = (left + right) / 2, i;
maxLeftSum = maxSubArray(nums, left, mid);
maxRightSum = maxSubArray(nums, mid + 1, right);
maxLeftBorderSum = 0, leftBorderSum = 0;
for(i = mid; i >= left; i--){
leftBorderSum += nums[i];
if(leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
maxRightBorderSum = 0, rightBorderSum = 0;
for(i = mid + 1; i <= right; i++){
rightBorderSum += nums[i];
if(rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
int maxSubArrayAns(int nums[]){
return maxSubArray(nums, 0, MAX_N - 1);
}
使用分治法的话,平均时间复杂度为Θ(n lg n)。
---------------------
作者:丧乱
来源:CSDN
原文:https://blog.csdn.net/u014235934/article/details/51996493
所学知识汇总
分治法的实现应用
发现问题汇总
尽量使得编写代码的过程流畅通顺,提前想好特殊情况判断
总结
思考了很多备受启发,再次感谢大佬,希望以后的代码可以用上~