算法導論中最大子序列4種解法

算法導論看到了第4章的分治策略,裏面講述到了最大子序列的分治求法,下面我用代碼實現出來吧:

 

分治法

我們先看書中給的僞代碼與思想:

當最大的跨越中間的一點,分別找左右的值最大值,然後在加起來。

當不是跨越的時候使用左右各自使用分治。

代碼如下:


//分治法
class Solution
{
public:
	int maxSubArray(vector<int> &nums)
	{
		//類似尋找最大最小值的題目,初始值一定要定義成理論上的最小最大值
		int result = INT_MIN;
		int numsSize = int(nums.size());
		result = maxSubArrayHelper(nums, 0, numsSize - 1);
		return result;
	}

	int maxSubArrayHelper(vector<int> &nums, int left, int right)
	{
		if (left == right)
		{
			return nums[left];
		}
		int mid = (left + right) / 2;
		int leftSum = maxSubArrayHelper(nums, left, mid);
		//注意這裏應是mid + 1,否則left + 1 = right時,會無線循環
		int rightSum = maxSubArrayHelper(nums, mid + 1, right);
		int midSum = findMaxCrossingSubarray(nums, left, mid, right);
		int result = max(leftSum, rightSum);
		result = max(result, midSum);
		return result;
	}

	int findMaxCrossingSubarray(vector<int> &nums, int left, int mid, int right)
	{
		int leftSum = INT_MIN;
		int sum = 0;
		for (int i = mid; i >= left; i--)
		{
			sum += nums[i];
			leftSum = max(leftSum, sum);
		}

		int rightSum = INT_MIN;
		sum = 0;
		//注意這裏i = mid + 1,避免重複用到nums[i]
		for (int i = mid + 1; i <= right; i++)
		{
			sum += nums[i];
			rightSum = max(rightSum, sum);
		}
		return (leftSum + rightSum);
	}
};

分治法我們看了後,發現它的時間複雜度是

通常我們最先想到的是暴力法,當然時間複雜度當然是最高了:

暴力解析:

代碼上:

//方法1,暴力法遍歷全部數據
int maxSubArray1(vector<int> & nums)
{
	//類似尋找最大最小值的題目,初始值一定要定義成理論上的最小最大值
	int max = INT_MIN;
	size_t numsSize = nums.size();
	for (int i = 0; i<numsSize; i++)
	{
		int sum = 0;
		for (int j = i; j<numsSize;j++)
		{
			sum += nums[j];
			if (sum > max)
			{
				max = sum;

			}
		}
	}
	return max;
}

這個就比較簡單了,直接記錄所有的大小,然後比較出最大值。時間複雜度就是 n^2 了

下面的方法可以解決時間複雜度使得複雜度爲:n

動態規劃:

int maxSubArray2(vector<int> &nums)
{
	//類似尋找最大最小值的題目,初始值一定要定義成理論上的最小最大值
	int result = INT_MIN;
	size_t numsSize = int(nums.size());

	//dp[i]表示nums中以nums[i]結尾的最大子序和
	vector<int> dp(numsSize);
	dp[0] = nums[0];
	result = dp[0];
	for (size_t i = 1; i < numsSize; i++)
	{
		dp[i] = max(dp[i - 1] + nums[i], nums[i]);
		result = max(result, dp[i]);
	}
	return result;
}

動態規劃就是喜歡記錄數據然後進行判斷,比較經典的是這句代碼:

dp[i] = max(dp[i - 1] + nums[i], nums[i]);
result = max(result, dp[i]);

        之前的數據 + 當前數據   如果小於  當前數據,直接就要當前的數據了。如果大於當前數據,我們繼續加,要麼碰到後面的當前數據比較大,要麼累加的數據,都比當前的大,最後都要與result(記錄的最大值做比較)。

      最終可以找到最大值了,是不是非常的簡單。

下面的一步大家比較熟悉的貪婪算法:

//貪心算法
int maxSubArray3(vector<int> &nums)
{
	//類似尋找最大最小值的題目,初始值一定要定義成理論上的最小最大值
	int result = INT_MIN;
	int numsSize = int(nums.size());
	int sum = 0;
	for (int i = 0; i < numsSize; i++)
	{
		sum += nums[i];
		result = max(result, sum);
		//如果sum < 0,重新開始找子序串
		if (sum < 0)
		{
			sum = 0;
		}
	}
	return result;
}

喜歡的朋友可以關注加收藏。一起學習與成長。

參考連接:

https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-cshi-xian-si-chong-jie-fa-bao-li-f/

算法導論的習題,現在是不是都明白了。

 

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