4_Sum

该博客介绍了如何解决LeetCode上的四数之和问题,即找到数组中和为目标值的不重复四元组。博主分析了两种方法,一种是通过两两配对再夹逼,另一种是利用哈希表存储两数之和,然后进行夹逼操作。这两种方法都以O(n)的时间复杂度实现了问题的解决方案,并确保了结果的唯一性。

1.问题描述

LeetCode:
Given an array S of n integers, are there elements a; b; c, and d in S such that a+b+c+d = target?
Find all unique quadruplets in the array which gives the sum of target.
Note:
Elements in a quadruplet (a; b; c; d) must be in non-descending order. (ie, a <= b <= c <= d)
The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0.
A solution set is:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)

2.问题分析

使用一个hashmap缓存两个数之和,两边夹逼。

3.代码

//时间复杂度O(n),空间复杂度O(1)
class Solution
{
public:
	vector<vector<int> > fourSum(vector<int> &num, int target)
	{
		vector<vector<int> >result;
		if(num.size() < 4)return result;
		sort(num.begin(), num.end());

		auto last = num.end();
		for(auto a = num.begin();a < prev(last,3);++a)
		{
			for(auto b = next(a);b < prev(lasr,2);++b)
			{
				auto c = next(b);
				auto d = prev(last);
				while(c < d)
				{
					if(*a + *b + *c + *d < target)
						++c;
					else if(*a + *b + *c + *d < target)
						--d;
					else
					{
						result.push_back({*a,*b,*c,*d});
						++c;
						--d;
					}
				}
			}
		}
		sort(result.begin(),result.end());
		result.erase(unique(result.begin(),result.end()),result.end());
		return result;
	}
};

class Solution
{
public:
	vector<vector<int> > fourSum(vector<int> &num, int target)
	{
		vector<vector<int> >result;
		if(num.size() < 4) return result;
		sort(num.begin(), num.end());

		unordered_map<int, vector<pair<int, int> >cache;
		for(size_t a = 0; a < num.size(); ++a)
		{
			for(size_t b = a+1;b < num.size();++b)
			{
				cache[num[a]+num[b]].push_back(pair<int,int>(a,b));
			}
		}
		
		for(size_t c = 0; c < num.size(); ++c)
		{
			for(size_t d = c+1; d < num.size(); ++d)
			{
				const int key = target - num[a] -num[b];
				if(cache.find(key) == cache.end()) continue;

				const auto& vec = cache[key];
				for(size_t k = 0;k < vec.size();++k)
				{
					if(c <= vec[k].second)
						continue;

					result.push_back({num[vec[k].first],num[vec[k].second],num[c],num[d]});
				}
			}
		}
		sort(result.begin(),result.end());
		result.erase(unique(result.begin(),result.end()),result.end());
		return result;
	}
};

4.总结

两个方法,一个是先固定两个数,再使用夹逼;二是使用一个hashmap缓存两个数的和,再使用夹逼。

<think>首先,用户的问题是关于给定的C语言程序段在输入8和输入5时的运行结果。程序段如下: ```c int i, max_sum, n, this_sum; int a[ ] = {-1, 3, -2, 4, -6, 1, 6, -1}; scanf("%d", &n); max_sum = this_sum = 0; for( i = 0; i < n; i++ ) { this_sum += a[i]; if( this_sum > max_sum ) max_sum = this_sum; else if( this_sum < 0 ) this_sum = 0; } printf("%d\n", max_sum); ``` 我需要计算当输入n=8和n=5时的输出。 ### 分析程序功能 这个程序实现了最大子数组和问题(类似于Kadane's algorithm)。数组`a`是给定的:{-1, 3, -2, 4, -6, 1, 6, -1}。 - `max_sum` 存储最大子数组和。 - `this_sum` 存储当前子数组和。 - 初始化时,`max_sum`和`this_sum`都为0。 - 循环遍历数组元素: - 将当前元素加到`this_sum`。 - 如果`this_sum`大于`max_sum`,更新`max_sum`。 - 如果`this_sum`小于0,则重置`this_sum`为0(因为负和不会对后续子数组有贡献)。 ### 计算输入n=8时 数组有8个元素:{-1, 3, -2, 4, -6, 1, 6, -1}。 我需要模拟循环过程,跟踪`i`, `this_sum`, `max_sum`。 | i | a[i] | this_sum (before add) | this_sum (after add) | max_sum | action | |---|------|------------------------|-----------------------|---------|-----------------| | 0 | -1 | 0 | -1 | 0 | this_sum < 0, reset to 0 | | 1 | 3 | 0 | 3 | 3 | update max_sum | | 2 | -2 | 3 | 1 | 3 | no update | | 3 | 4 | 1 | 5 | 5 | update max_sum | | 4 | -6 | 5 | -1 | 5 | this_sum < 0, reset to 0 | | 5 | 1 | 0 | 1 | 5 | no update | | 6 | 6 | 1 | 7 | 7 | update max_sum | | 7 | -1 | 7 | 6 | 7 | no update | 所以,最终max_sum = 7。 ### 计算输入n=5时 输入n=5,只处理前5个元素:{-1, 3, -2, 4, -6}。 | i | a[i] | this_sum (before add) | this_sum (after add) | max_sum | action | |---|------|------------------------|-----------------------|---------|-----------------| | 0 | -1 | 0 | -1 | 0 | this_sum < 0, reset to 0 | | 1 | 3 | 0 | 3 | 3 | update max_sum | | 2 | -2 | 3 | 1 | 3 | no update | | 3 | 4 | 1 | 5 | 5 | update max_sum | | 4 | -6 | 5 | -1 | 5 | this_sum < 0, reset to 0 | 最终max_sum = 5。 ### 总结结果 - 输入n=8时,输出7。 - 输入n=5时,输出5。 ### 回答结构 我需要结构化回答: - 解释程序功能。 - 逐步计算两个输入。 - 给出输出。 使用中文回答。 ### 添加相关问题 根据指令,生成相关问题。 ### 引用(如果需要) 用户提供了引用,但在这个问题中,引用似乎不直接相关。我可以不引用,除非必要。 ### 格式要求 - 行内数学表达式用$...$。 - 独立公式用$$...$$。 - 这里可能不需要复杂数学,但如果有变量,用$格式。 在描述数组索引时,可以用$i$等。 ### 完整回答 1. **解释程序**:这是一个求解最大子数组和的程序。 2. **数组定义**:a[] = {-1, 3, -2, 4, -6, 1, 6, -1}。 3. **输入n=8时**:模拟过程,输出7。 4. **输入n=5时**:模拟过程,输出5。 5. **相关问题**:生成2-3个相关问题。 </think>### C语言程序运行结果分析 给定程序实现了最大子数组和算法(类似于Kadane's算法),用于计算数组$a$中指定长度$n$的最大连续子数组和[^1]。数组定义为: ```c int a[ ] = {-1, 3, -2, 4, -6, 1, 6, -1}; ``` 算法核心逻辑: - `this_sum`跟踪当前子数组和,若为负则重置为$0$。 - `max_sum`记录遍历过程中的最大和。 - 循环遍历前$n$个元素,动态更新和值。 下面分析输入$n=8$和$n=5$时的运行结果。 --- #### 1. **输入 $n=8$ 时的运行结果** 当$n=8$时,程序处理整个数组`a[0]`到`a[7]`。模拟执行过程如下: | 迭代$i$ | $a[i]$ | `this_sum` 更新后 | `max_sum` 更新后 | 操作说明 | |---------|--------|-------------------|------------------|------------------------------| | 0 | $-1$ | $0 + (-1) = -1$ | 0 | `this_sum < 0`,重置为$0$ | | 1 | $3$ | $0 + 3 = 3$ | 3 | `this_sum > max_sum`,更新 | | 2 | $-2$ | $3 + (-2) = 1$ | 3 | 无更新 | | 3 | $4$ | $1 + 4 = 5$ | 5 | `this_sum > max_sum`,更新 | | 4 | $-6$ | $5 + (-6) = -1$ | 5 | `this_sum < 0`,重置为$0$ | | 5 | $1$ | $0 + 1 = 1$ | 5 | 无更新 | | 6 | $6$ | $1 + 6 = 7$ | 7 | `this_sum > max_sum`,更新 | | 7 | $-1$ | $7 + (-1) = 6$ | 7 | 无更新 | 最终输出:`printf`打印`max_sum`的值为$7$。 --- #### 2. **输入 $n=5$ 时的运行结果** 当$n=5$时,程序处理前5个元素`a[0]`到`a[4]`。模拟执行过程如下: | 迭代$i$ | $a[i]$ | `this_sum` 更新后 | `max_sum` 更新后 | 操作说明 | |---------|--------|-------------------|------------------|------------------------------| | 0 | $-1$ | $0 + (-1) = -1$ | 0 | `this_sum < 0`,重置为$0$ | | 1 | $3$ | $0 + 3 = 3$ | 3 | `this_sum > max_sum`,更新 | | 2 | $-2$ | $3 + (-2) = 1$ | 3 | 无更新 | | 3 | $4$ | $1 + 4 = 5$ | 5 | `this_sum > max_sum`,更新 | | 4 | $-6$ | $5 + (-6) = -1$ | 5 | `this_sum < 0`,重置为$0$ | 最终输出:`printf`打印`max_sum`的值为$5$。 --- ### 总结 - **输入 $n=8$ 时输出**:$7$ - **输入 $n=5$ 时输出**:$5$ 程序通过动态规划高效求解子数组最大和[^1],关键点在于及时重置和为负的子序列。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值