Leetcode_Ksum题目总结

6 篇文章 0 订阅
1 篇文章 0 订阅


Letcode上面有几道关于K sum的问题,做起来感觉还挺麻烦,花了挺长时间做了一个适用于任意个k的通用版本,在这里总结一下,如果有更好的方法,还请不吝赐教。


问题描述:

Two Sum

Given an array of integers, find two numbers such that they add up to a specific target number.

Three Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

4Sum

 

Given an array S of n integers, are there elements abc, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.


解题思路:

1. 暴力枚举,相信这是每个人都能想到的办法,时间复杂度是随着k的增长而指数增长O(N^k)

2.利用排序。

首先讨论k = 2的情况,

k = 2时,使用两个指针low and high,一个指向头,一个指向尾。找sum 为target的pair, 如果sum == target,记录下该对pair, low++; 如果sum < target, low++; 如果 sum >target high--. 直到 high ==  low, 时间复杂度为排序时间加线性遍历时间 O(nlogn + n),所以即为(nlogn)

接下来分析k > 2的情况, 

这里可以用到递归解决子问题的思想,我们可以将k = 3 找寻 target 的问题 看成 k = 2 找寻 target - num[i] 的问题,即每次假设某一元素num[i] 在结果中,在剩余数组元素中,找寻满足 sum  = target - num[i] 的元素pair。

该思想可以推广到k为任意的情况。时间复杂度我不是特别确定,因为当问题规模规约到 k = 2时,时间复杂度为O(nlogn),所以整体时间复杂度应该是O(n^(k-1))。如果有错误,欢迎指出


算法思想大概就是如上所述,但是还有很多实现细节问题,

1) 去重,题目要求我们返回一个vector<vector<int> > ,其中按non-decreasing 且不能有重复的结果。我看到网上很多人讨论这个问题,用到什么map,set... 感觉很麻烦而且完全没必要,简单分析可知,数组已经是有序,出现重复结果无非是连续相同元素所致,例如, 3 3 7 7 7 ,如果我们已经得到了以第一个7开头的正确结果vector, 那么我们不需要接下来 以 7 开头的任何结果vector,因为在解第一个以7开头的结果vector时,我们已经得到了所有以7开头的正确结果,那么这时我们应该大胆跳过。

所以,在扫描时,我们添加一个判断条件,只有当前一个元素和当前元素不相同时,或者是第一个元素(之前没有元素) ,我们才执行求解。


上CODE


vector<vector<int> > myfunction(vector<int>& num, int target, int k, int begin){
	if(k == 2){
		map<int,bool> existed;
		vector<vector<int> > ret;
		int low = begin;
		int high = num.size() - 1;
		while(low < high){
			int tempsum = num[low] + num[high];
			if(tempsum == target){
				if(existed.find(num[low]) == existed.end()){
					existed[num[low]] = true;
					vector<int> tempret;
					tempret.push_back(num[low]);
					tempret.push_back(num[high]);
					ret.push_back(tempret);
				}
				++low;
			}else if(tempsum < target)++low;
			else
				--high;
		}
		return ret;
	}else{
		vector<vector<int> > cot;
		if(num.size()-begin < k)return cot;
		for(int i = begin; i < num.size() - (k - 1); ++i){
			if(i == begin || num[i] != num[i-1]){
				vector<vector<int> > ret = myfunction(num,target - num[i], k - 1, i + 1);
				for(int p = 0; p < ret.size(); ++p){
					vector<int> tempret;
					tempret.push_back(num[i]);
					for(int q = 0; q < ret[p].size(); ++q){
						tempret.push_back(ret[p][q]);
					}
					cot.push_back(tempret);
				}
			}
		}
		return cot;
	}
}

vector<vector<int> > ksum(vector<int>& num, int target, int k){
	sort(num.begin(),num.end());
	return myfunction(num,target,k,0);
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值