最大子序列和问题求解

算法1

  • 算法思想
基本思想:穷举式的尝试所有可能,通过三层循环计算所有子序列的和。
算法步骤:
1.第一层循环从0到N-1,确定子序列的开始位置;
2.第二层循环从第一层循环变量开始到N-1,确定子序列的结束位置;
3.第三层循环从第一层循环变量开始到第二层循环变量结束,计算这个子序列的和,并与最大子序列和比较,如果大于最大子序列和就赋值给最大子序列和。
  • 运行时间
O(N³)
  • 算法实现
int MaxSubSequenceSum_1(int A[], int N)
{
	int ThisSum, MaxSum,i, j, k;

	MaxSum = 0;
	for(i=0;i<N;i++)
		for (j = i; j < N; j++)
		{
			ThisSum = 0;
			for (k = i; k <= j; k++)
				ThisSum += A[k];
			if (ThisSum > MaxSum)
			{
				MaxSum = ThisSum;
			}
		}	
	return MaxSum;
}









算法2

  • 算法思想
基本思想:穷举所有可能,通过两层循环实现,与第一个算法相比较,减小了第三层循环,不需要每次都从第一层循环变量的位置开始累加子序列。
算法步骤:
1.第一层循环从0到N-1,确定子序列的初始位置;
2.第二层循环从第一层的循环变量开始到N-1,对当前序列和进行累加数组中的元素,并与最大子序列和比较,如果大于最大子序列和,则赋值给最大子序列和。

  • 运行时间
O(N²)
  • 算法实现
    int MaxSubSequenceSum_2(int A[],int N)
    {
    	int ThisSum, MaxSum, i, j;
    	MaxSum = 0;
    	for (i = 0; i < N; i++)
    	{
    		ThisSum = 0;
    		for (j = i; j < N; j++)
    		{
    			ThisSum += A[j];
    			if (ThisSum > MaxSum)
    				MaxSum = ThisSum;
    		}
    	}
    	return MaxSum;
    }



算法3

  • 算法思想
基本思想:通过分治思想,最大子序列和可能在三处出现,或者整个出现在输数据的左半部,或者整个出现在右半部,或者跨越输入数据的中部从而占据左右两部分。前两种情况递归求解,第三种情况的最大和通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到。
算法步骤:
1.递归的基准情况处理,及如果Left==Right,并且当该元素最大时,它就是最大子序列;
2.计算序列的中间值并,递归求解最大子序列在全部在左半部分出现,或者全部在右半部份出现的情况;
3.使用两个循环分别计算前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素);
4.返回三种情况计算出最大和的最大一种情况并返回。
  • 运行时间
O(N log N)
  • 算法实现
int Max3(int i, int j, int k)
{
	return k > (i > j ? i : j) ? k : (i > j ? i : j);

}

int MaxSum(int A[],int Left,int Right)
{
	int MaxLeftSum, MaxRightSum;
	int MaxLeftBoderSum, MaxRightBoderSum;
	int LeftBoderSum, RightBoderSum;
	int center, i;

	if (Left == Right)
		if (A[Left] > 0)
			return A[Left];
		else
			return 0;

	center = (Left + Right) / 2;
	MaxLeftSum = MaxSum(A, Left, center);
	MaxRightSum = MaxSum(A, center + 1, Right);

	LeftBoderSum = MaxLeftBoderSum = 0;
	for (i = center; i >= Left; i--)
	{
		LeftBoderSum += A[i];
		if (LeftBoderSum > MaxLeftBoderSum)
			MaxLeftBoderSum = LeftBoderSum;
	}

	RightBoderSum = MaxRightBoderSum = 0;
	for (i=center+1;i<=Right;i++)
	{
		RightBoderSum += A[i];
		if (RightBoderSum > MaxRightBoderSum)
			MaxRightBoderSum = RightBoderSum;
	}

	return Max3(MaxLeftSum, MaxRightSum, MaxLeftBoderSum+ MaxRightBoderSum);

}


int MaxSubSequenceSum_3(int A[], int N)
{
	return MaxSum(A, 0, N - 1);
}


算法4

递归实现:


int mymaxSubArray(vector<int>& nums ,int i,int* pointTomaxSum)
{

	int thisSum;
        int temp;
	if (i == 0)
		return nums[i];
    else
        temp = mymaxSubArray(nums, i - 1,pointTomaxSum);
	thisSum =(temp>0 ? temp : 0) + nums[i];
	*pointTomaxSum = max(thisSum, *pointTomaxSum);
	return thisSum;
}

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int *pointTomaxSum;
        int maxSum=nums[0];
        pointTomaxSum=&maxSum;                    
        mymaxSubArray(nums,nums.size()-1,pointTomaxSum);      
        return maxSum;
    }
};


算法5

动态规划实现:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int len=nums.size();
        vector<int> thisSum(len);
        thisSum[0]=nums[0];
        int maxSum=nums[0];
        for(int i=1;i<len;i++){
            thisSum[i]=nums[i]+(thisSum[i-1] >0 ? thisSum[i-1] :0);
            maxSum=max(thisSum[i],maxSum);
        }
      return maxSum;
    }
};


时间:O(N)  
空间:O(N)

动态规划改进:

因为只需要保存上次计算的总和就可以了,不需要用数组维持每次计算后的总和。

修改后的代码:
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int len=nums.size();
        //vector<int> thisSum(len);
        int thisSum=nums[0];
        //thisSum[0]=nums[0];
        int maxSum=nums[0];
        for(int i=1;i<len;i++){
            thisSum=nums[i]+(thisSum >0 ? thisSum :0);
            maxSum=max(thisSum,maxSum);
        }
      return maxSum;
    }
};

或者从0开始,这样修改;
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int len=nums.size();
        //vector<int> thisSum(len);
        int thisSum=0;
        //thisSum[0]=nums[0];
        int maxSum=nums[0];
        for(int i=0;i<len;i++){
            thisSum=nums[i]+(thisSum >0 ? thisSum :0);
            maxSum=max(thisSum,maxSum);
        }
      return maxSum;
    }
};


时间:O(N)
空间:O(1)



算法6

  • 算法思想
基本思想:从数组的第一个元素开始累加到子序列和,当子序列和大于最大子序列和,则将子序列和赋值给最大子序列和,否则判断子序列和是否小于0,小于0就将子序列和赋值0。这句话的意思是前面所有序列和为负数的话,就抛弃前面的所有序列,从当前序列重新累加,因为将前面的序列加入会使得和变小。</div><div>说明:该算法一个附带的优点是,它只对数据进行一次扫描,一旦A[i]被读入并被处理,它就不再需要被记忆。不仅如此,在任意时刻,算法都呢个对它已经读入的书给出子序列问题的正确答案。具有这种性质的算法叫做联机算法(on-line algorithm)。
算法步骤:
1.一个循环从0到N-1,实现对所有元素的遍历;
2.将每个元素累加到子序列和,如果子序列和大于最大子序列和,就赋值给最大子序列和,否则判断子序列和是否小于0,小于0就将子序列和赋值0。
  • 运行时间
O(N)
  • 算法实现

long long MaxSubSequenceSum_4(long  long A[], long long N)
{
	 long long ThisSum,MaxSum,i;
	ThisSum=0;
        MaxSum=A[0];  //注意,最大值可能是第一个元素
	for(i=0;i<N;i++)
	{
		ThisSum+=A[i];

		if(ThisSum>MaxSum)
			MaxSum=ThisSum;
	        if(ThisSum<0)    //不能添加else
			ThisSum=0;
	}
	return  MaxSum;
}




### 最大子序列问题的C语言实现 最大子序列问题是经典的算法问题之一,其目标是从给定的一维数组中找出具有最大的一个连续子数组。以下是基于动态规划的思想来解决问题的一种高效解决方案。 #### 动态规划的核心思路 通过维护一个状态变量 `dp[i]` 表示以第 `i` 个元素为结尾的最大子数组,可以逐步更新并最终得到全局最优解。这种方法的时间复杂度为 O(n),空间复杂度可以通过优化降低至 O(1)[^2]。 下面是完整的 C 语言代码实现: ```c #include<stdio.h> long long num[200001]; long long dp[200001]; int max(int x, int y) { return (x > y) ? x : y; } int main() { int n, i, max_sum; while (scanf("%d", &n) != EOF) { for (i = 1; i <= n; i++) { scanf("%lld", &num[i]); } dp[1] = num[1]; max_sum = dp[1]; for (i = 2; i <= n; i++) { dp[i] = max(dp[i - 1] + num[i], num[i]); // 键转移方程 if (max_sum < dp[i]) { max_sum = dp[i]; // 更新当前最大值 } } printf("%lld\n", max_sum); } return 0; } ``` 上述程序实现了动态规划求解最大子序列的方法。其中核心部分是对每个位置上的元素决定是否将其加入之前的子数组还是重新开始一个新的子数组,这一步骤由表达式 `dp[i] = max(dp[i-1] + num[i], num[i])` 完成。 如果希望进一步减少内存消耗,则可以直接省去存储整个 `dp[]` 数组的需求,在迭代过程中仅保留上一次的结果即可[^4]。 #### 另一种暴力枚举方式 除了高效的动态规划方法外,还可以采用双重循环的方式逐一尝试所有可能的子数组组合,并记录下最大的那个总。不过该策略效率较低,时间复杂度达到 O(n²)[^3]。 ```c #include <stdio.h> #define MAXN 1000 int maxsum(const int arr[], int N) { int this_sum, max_sum; max_sum = 0; for (int i = 0; i < N; i++) { // 子数组起始位置 this_sum = 0; for (int j = i; j < N; j++) { // 子数组结束位置 this_sum += arr[j]; if (this_sum > max_sum) { max_sum = this_sum; } } } return max_sum; } int main() { int arr[MAXN]; int N; scanf("%d", &N); for (int i = 0; i < N; i++) { scanf("%d", &arr[i]); } printf("%d\n", maxsum(arr, N)); return 0; } ``` 尽管此版本易于理解,但在处理大规模输入时性能表现不佳,因此推荐优先考虑更优的算法设计如前面提到过的动态规划技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值