求子数组的最大值之和并给出子数组的下标

本文介绍了一种方法来求解给定数组中子数组的最大和,并提供子数组的起始和结束下标。通过遍历数组并利用状态变量记录当前和最大和,该方法能够有效地找到所需子数组。

如题:求子数组的最大值之和并给出子数组的下标

参考文献:http://blog.youkuaiyun.com/bertzhang/article/details/7242497

                  http://blog.youkuaiyun.com/zsuguangh/article/details/6337410

下面给出一种方法:

#include "stdafx.h"
#include<iostream>
using namespace std;

int maxsum(int a[],int n,int *start,int *end)
{
    int laststart;
    int lastmax = a[0];
	int max = 0;
	if(a == NULL || n == 0)
	{
		return NULL;
	}		 
	for(int i = 0; i< n; i++)
	{
		max = max + a[i];
		if(max > lastmax)
		{
			lastmax = max;
			*end = i;
		}
		if(max <= 0 )
		{
			max = 0;
			if(i < n)
			{
				laststart = i + 1;
			}
		}
        if(max == lastmax)
        {
            *start = laststart;
        }
	}
	return lastmax;
}

int main()
{
	int array[]= {-1,2,-3,4,5,6,7,-9,-19,4,3};	
	int start = 0;
	int end = 0;
	cout<< maxsum(array,sizeof(array)/sizeof(int),&start,&end)<<endl;
	cout<<start<<"  "<<end<<endl;
	system("pause");
	return 0;
}


 



<think>我们参考了多个递归数组最大值的实现方法。根据引用[2]引用[3]提供的C语言代码,我们可以总结出两种常见的递归思路: 思路1:将数组从中间分成两部分,分别递归出左半部分右半部分的最大值,然后返回这两个最大值中的较大者(分治法)。 思路2:将数组分解为第一个元素剩余元素组成的子数组,递归求子数组最大值,然后与第一个元素比较取较大值(线性递归)。 我们分别实现这两种方法: 方法1(分治法): - 递归函数:`int maxArr(int arr[], int left, int right)` - 基线条件(递归终止条件):当区间只有一个元素(即left==right)时,返回该元素。 - 递归步骤:将当前区间[left, right]分成两个子区间,分别递归解两个子区间的最大值,然后比较两个最大值得到整个区间的最大值。 方法2(线性递归): - 递归函数:`int maxElement(int arr[], int n)` 或 `int maxElement(int arr[], int start, int end)` - 基线条件:当子数组只有一个元素(即n==1或start==end)时,返回该元素。 - 递归步骤:比较当前子数组的第一个元素(例如arr[0]或arr[start])与剩余子数组最大值(递归得)的大小,返回较大值。 下面我们分别用两种方法实现: 方法1(分治法)代码(参考引用[4]): ```c #include <stdio.h> // 使用分治法递归数组最大值 int maxArr(int arr[], int left, int right) { // 基线条件:当区间只有一个元素 if (left == right) { return arr[left]; } // 将区间分成两部分(取中间位置) int mid = left + (right - left) / 2; // 防止直接相加溢出 // 递归左半部分最大值 int leftMax = maxArr(arr, left, mid); // 递归右半部分最大值 int rightMax = maxArr(arr, mid + 1, right); // 返回左右两部分的最大值 return leftMax > rightMax ? leftMax : rightMax; } int main() { int arr[] = {1, 23, 456, 2, 436, 8, 33}; int n = sizeof(arr) / sizeof(arr[0]); int max = maxArr(arr, 0, n - 1); printf("数组最大值: %d\n", max); return 0; } ``` 方法2(线性递归)代码(参考引用[3]): ```c #include <stdio.h> // 使用线性递归数组最大值 int maxElement(int arr[], int n) { // 基线条件:当数组只有一个元素 if (n == 1) { return arr[0]; } // 递归前n-1个元素的最大值 int max = maxElement(arr, n - 1); // 将前n-1个元素的最大值与当前最后一个元素(arr[n-1])比较 return max > arr[n - 1] ? max : arr[n - 1]; } // 另一种参数形式:使用起始位置结束位置 int maxElement2(int arr[], int start, int end) { if (start == end) { return arr[start]; } int subMax = maxElement2(arr, start + 1, end); return arr[start] > subMax ? arr[start] : subMax; } int main() { int arr[] = {1, 23, 456, 2, 436, 8, 33}; int n = sizeof(arr) / sizeof(arr[0]); int max1 = maxElement(arr, n); int max2 = maxElement2(arr, 0, n - 1); printf("方法1最大值: %d\n", max1); printf("方法2最大值: %d\n", max2); return 0; } ``` 注意: 方法1(分治法)的时间复杂度为$O(n)$,因为每个元素都被访问了一次,递归深度为$O(\log n)$,但由于每一层都要访问所有元素,所以总时间复杂度为$O(n)$(实际上由于分治的方式,每一层合起来都是整个数组,所以是$O(n)$)。然而,分治法的递归调用次数比线性递归多,但递归深度较小(对数级),而线性递归的递归深度是$O(n)$。 方法2的线性递归版本(maxElement)通过不断缩小数组长度(每次减1)来递归,递归深度为$n$(数组长度),当数组很大时可能导致栈溢出。而分治法的递归深度大约为$\log_2 n$,但函数调用次数较多。 根据需,用户要使用C语言递归方法数组最大值,以上两种方法均可。用户可以根据实际情况选择。 另外,引用[3]中的代码实现的是线性递归(从后往前比较),我们这里提供了两种线性递归的写法(一种用数组长度,一种用下标范围)。 在实现时,注意数组为空的情况,但根据题目,我们假设数组至少有一个元素。 最后,我们输出完整的可运行代码供用户测试。 由于用户要使用C语言,我们提供分治法线性递归两种实现,给出示例主函数。 完整代码(包含两种方法): ```c #include <stdio.h> // 方法1:分治法 int maxArr(int arr[], int left, int right) { if (left == right) { return arr[left]; } int mid = left + (right - left) / 2; int leftMax = maxArr(arr, left, mid); int rightMax = maxArr(arr, mid + 1, right); return leftMax > rightMax ? leftMax : rightMax; } // 方法2:线性递归(通过数组长度) int maxElement(int arr[], int n) { if (n == 1) { return arr[0]; } int max = maxElement(arr, n - 1); return max > arr[n - 1] ? max : arr[n - 1]; } // 方法3:线性递归(通过下标) int maxElement2(int arr[], int start, int end) { if (start == end) { return arr[start]; } int subMax = maxElement2(arr, start + 1, end); return arr[start] > subMax ? arr[start] : subMax; } int main() { int arr[] = {1, 23, 456, 2, 436, 8, 33}; int n = sizeof(arr) / sizeof(arr[0]); // 测试分治法 int max1 = maxArr(arr, 0, n - 1); printf("分治法最大值: %d\n", max1); // 测试线性递归(数组长度) int max2 = maxElement(arr, n); printf("线性递归(数组长度)最大值: %d\n", max2); // 测试线性递归(下标) int max3 = maxElement2(arr, 0, n - 1); printf("线性递归(下标最大值: %d\n", max3); return 0; } ``` 运行上述代码,将输出: 分治法最大值: 456 线性递归(数组长度)最大值: 456 线性递归(下标最大值: 456 用户可以根据自己的需要选择其中一种方法。 注意:在实际应用中,递归方法可能因为递归深度过大而导致栈溢出,尤其是线性递归在数组很大时。因此,对于大规模数组,建议使用迭代法(循环)来最大值,或者使用分治法(递归深度较小)。如果必须使用递归,分治法更安全。 另外,上述代码没有处理数组为空的情况,如果可能传入空数组,需要额外判断。 根据用户要,我们提供了C语言递归数组最大值的解决方案。 </think> 以下是使用C语言通过递归方法数组最大值的完整解决方案,结合了引用中的最佳实践: ### 方法1:线性递归(分治思想) ```c #include <stdio.h> int findMax(int arr[], int start, int end) { if (start == end) { // 基线条件:只有一个元素 return arr[start]; } int mid = start + (end - start) / 2; // 防止整数溢出 int leftMax = findMax(arr, start, mid); // 递归左半部分 int rightMax = findMax(arr, mid + 1, end); // 递归右半部分 return (leftMax > rightMax) ? leftMax : rightMax; // 合结果 } int main() { int arr[] = {1, 23, 456, 2, 436, 8, 33}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组最大值: %d\n", findMax(arr, 0, n - 1)); return 0; } ``` **算法分析**: 1. **时间复杂度**:$O(n)$,每个元素被访问一次 2. **空间复杂度**:$O(\log n)$,递归栈深度 3. **核心思想**:将数组分为左右两半,递归子数组最大值,然后比较合结果[^4] ### 方法2:尾递归优化(减少栈深度) ```c #include <stdio.h> int tailRecursiveMax(int arr[], int start, int end, int currentMax) { if (start > end) return currentMax; if (arr[start] > currentMax) currentMax = arr[start]; return tailRecursiveMax(arr, start + 1, end, currentMax); // 尾递归调用 } int main() { int arr[] = {1, 23, 456, 2, 436, 8, 33}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组最大值: %d\n", tailRecursiveMax(arr, 0, n - 1, arr[0])); return 0; } ``` **优势**: - 编译器可优化为迭代,避免栈溢出[^3] - 空间复杂度降为$O(1)$(优化后) ### 关键知识点解析 1. **基线条件**:当子数组长度为1时直接返回元素值(递归终止条件) 2. **递归分解**:将问题划分为更小的子问题(分治策略) 3. **合结果**:通过`max()`函数比较子问题结果 4. **边界处理**:空数组检查(示例省略,实际需添加) > **注意**:递归深度限制可能导致栈溢出,大数组建议使用迭代法: > ```c > int iterativeMax(int arr[], int n) { > int max = arr[0]; > for(int i = 1; i < n; i++) > if(arr[i] > max) max = arr[i]; > return max; > } > ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值