算法导论中最大子序列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/

算法导论的习题,现在是不是都明白了。

 

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