算法實現--求和爲s的連續正數序列.

求和爲s的連續正數序列.

如,輸入9,輸出序列:{2,3,4}、和{4,5}

下面是暴力循環法:

// 暴力法
vector<vector<int>> FindContinuousSequence(int target) {
	int sum = 0;
	vector<vector<int>> result;
	for (int i = 1; i <= target / 2; ++i)
	{
		for (int j = i; j < target; ++j)
		{
			sum += j;
			if (sum == target)
			{
				vector<int> temp;
				for (int k = i; k <= j; ++k)
				{
					temp.push_back(k);
				}
				result.push_back(temp);
				break;
			}
			else if (sum > target)
				break;
		}
		sum = 0;
	}
	return result;
}

 

下面是雙指針法,也就是滑動窗口法:時間複雜度O(n)

滑動窗口的重要性質是:窗口的左邊界和右邊界永遠只能向右移動,而不能向左移動。這是爲了保證滑動窗口的時間複雜度是 O(n)。如果左右邊界向左移動的話,這叫做“回溯”,算法的時間複雜度就可能不止 O(n)。

要用滑動窗口解這道題,我們要回答兩個問題:

第一個問題,窗口何時擴大,何時縮小?
第二個問題,滑動窗口能找到全部的解嗎?
對於第一個問題,回答非常簡單:

當窗口的和小於 target 的時候,窗口的和需要增加,所以要擴大窗口,窗口的右邊界向右移動
當窗口的和大於 target 的時候,窗口的和需要減少,所以要縮小窗口,窗口的左邊界向右移動
當窗口的和恰好等於 target 的時候,我們需要記錄此時的結果。設此時的窗口爲 [i, j)[i,j),那麼我們已經找到了一個 ii 開頭的序列,也是唯一一個 ii 開頭的序列,接下來需要找 i+1i+1 開頭的序列,所以窗口的左邊界要向右移動

// 雙指針法
vector<vector<int>> findContinuousSequence(int target) {
	int i = 1; // 右指針
	int j = 1; // 左指針
	int sum = 0;
	vector<vector<int>> result;
	while (i <= target / 2) // 考慮邊界,i可能爲target/2,如9/2=4
	{
		if (sum < target)
		{
			sum += j++;
		}
		else if (sum > target)
		{
			sum -= i++;
		}
		else
		{
			vector<int> temp;
			// 能進到這裏,上一次肯定是j++了,所以k<j爲結束條件
			for (int k = i; k < j; ++k)
			{
				temp.push_back(k);
			}
			result.push_back(temp);

			sum -= i++; // 注意要右移i
		}
	}
	return result;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章