Loading

四种算法实现最长连续子序列

#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>

using namespace std;

/*
产生长度为length的,元素为[-range,range)中随机数的vector
*/
vector<int> randomVector(int range, int length) {
	srand(time(0));
	vector<int> v(length);
	for (int i = 0; i < length; i++)
		v[i] = rand() % (range * 2) - range;
	return v;
}
/*
暴力破解 O(n^3)


Sum(i,j) = Sum of seq[i,j]

对于每个i,j,  0 <= i <= j < seq.size()
mcss = max(mcss,Sum(i,j))
*/
int MCSS1(vector<int> seq) {
	int mcss = seq[0];
	int tot = 0;
	for (int i = 0; i < seq.size(); i++) {
		for (int j = i; j < seq.size(); j++) {
			int sum = 0;
			for (int k = i; k <= j; k++) { sum += seq[k]; tot++; }
			mcss = max(mcss, sum);
		}
	}
	cout << "MCSS1,inner loop cnt: " << tot << endl;
	return mcss;
}

/*
O(n^2)算法

暴力破解算法有很大的时间上的浪费
考虑已经求出Sum(i,j)的情况下再求Sum(i,j+1)可以直接利用之前的Sum(i,j)的结果加上seq[j+1],而不用重新计算

设S(i) = Sum(0,i),则Sum(i,j) = S(j) - S(i-1)

这里就是利用了这一特性,记录序列中每个i( 0 <= i < seq.size )的前i项和,去掉内层循环
*/
int MCSS2(vector<int> seq) {
	int tot = 0;
	vector<int> S = { 0 }; 
	for (int i = 0; i < seq.size(); i++) { S.push_back(seq[i] + S[i]); tot++; }

	int mcss = seq[0];
	for (int i = 1; i < S.size(); i++) 
		for (int j = i; j < S.size(); j++) {
			tot++;
			mcss = max(mcss, S[j] - S[i - 1]);
		}
	cout << "MCSS2,inner loop cnt: " << tot << endl;
	return mcss;
}

/*
O(nlogn)算法


MCSS3(seq,l,r) 返回在seq[l,r)中的最大连续子序列和,那么MCSS3(seq,0,seq.size)为最终答案

设m为区间中间那个数,seq1为贯穿这个区间的最大连续子序列。

mcss = max(MCSS3(seq,l,m),MCSS3(seq,m,r),seq1)
*/
int MCSS3(vector<int> seq,int l,int r) {
	if (r - l == 1) return seq[l];
	int m = (l + r) / 2;
	int lMax = seq[m - 1], lSum = 0;
	for (int i = m - 1; i >= l; i--) {
		lSum += seq[i];
		lMax = max(lMax, lSum);
	}

	int rMax = seq[m], rSum = 0;
	for (int i = m; i < r; i++) {
		rSum += seq[i];
		rMax = max(rMax, rSum);
	}

	return max(max(MCSS3(seq, l, m), MCSS3(seq, m, r)), lMax + rMax);
}

/*
O(n)算法 动态规划

对于seq[i],它可以选择加入前面的连续子序列,也可以选择另开一个子序列。

当前面的连续子序列为负数时,选择另开一个子序列比较好,得到一个包含seq[i]的局部最大连续子序列
当前面的连续子序列为正数时,加入前面的子序列比较好,同样得到一个包含seq[i]的局部最大连续子序列

局部最大子序列中最大的那个即为答案。
*/
int MCSS4(vector<int> seq) {
	int mcss = seq[0],sum = seq[0];
	for (int i = 1; i < seq.size(); i++) {
		// 如果 sum是负数,选择另外开启一个新的序列,因为前面的sum对它无帮助
		if (sum < 0) { sum = 0; }
		sum += seq[i];
		// sum = max(sum+seq[i],seq[i]);
		mcss = max(sum, mcss);
	}
	return mcss;
}

int main() {
	vector<int> a = randomVector(1023, 100);// MCSS = 198

	cout << "MCSS1: " << MCSS1(a) << endl;
	cout << "MCSS2: " << MCSS2(a) << endl;
	cout << "MCSS3: " << MCSS3(a, 0, a.size()) << endl;
	cout << "MCSS4: " << MCSS4(a) << endl;


	return 0;
}
posted @ 2021-01-11 13:44  yudoge  阅读(310)  评论(0编辑  收藏  举报