LeetCode #015 3Sum

本文详细解析了LeetCode经典题目3Sum的求解方法,介绍了如何通过优化算法从O(N^3)的时间复杂度降至更高效的实现方式。文章分享了一种利用排序和双指针技巧来避免重复计算并简化搜索过程的有效策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题地址:https://leetcode.com/problems/3sum/

题目如下:

Total Accepted: 109833  Total Submissions: 590281  Difficulty: Medium

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.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.

    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)

Subscribe to see which companies asked this question

原始解题思路:求三数之和,就是两数之和问题(#001 原题链接:https://leetcode.com/problems/two-sum/;解法:http://blog.youkuaiyun.com/lengyan110/article/details/51018896)的升级版,将三数中两数之和作为原来两数问题中的第二个数。

代码实现思路:通过三重循环实现,嵌套遍历a,b,c,将结果(a,b,c)放入vector<vector <int> >对象中,时间复杂度O(N^3)。显然时间复杂度太高。

优化思路:(错误范例)由于受 #001题的影响,为了避免同一个数的重复遍历,我采用了internal作为间隔值,分组求和,然而这种方法下时间复杂度仍为O(N^3),并发现在数组中有大量冗余数据时,这种方法会将每个冗余数据都遍历出来,如数组 (-1,-1,0,1),则会输出两次(-1,0,1),因为在数组中 -1 出现了两次,并且看到范例输出中输出结果有序,考虑到要进行排序。

1)大量冗余数据

如这个数组 (-7,2,5,-7,2,-7,3,4,)依次遍历需要很多时间。

如果提前排序为(-7,-7,-7,2,2,3,4,5)在遍历第一个-7之后,跳转到第3个-7可以节约不少时间,正是考虑到这个,这里我们选择在数组刚读入时就进行排序,以便于以后比较相邻数如果相同的话执行“跳过”的操作。

2)排序

如1)分析,我们调用sort函数完成排序。


到这里,我们还需要解决两个问题:1、如何降低时间复杂度?           2、如何“跳过”相同的数?

这里借鉴了 CheukyinYip的方法(https://leetcode.com/discuss/94215/my-easy-understanding-cpp-code),抛弃了#001时用的internal。

在a遍历循环中,取b.index=a.index+1,c.index=nums.size()-1

这样的好处在于在遍历b的时候可以自左向右的“跳过”相同的值,同时在另一端自右向左的“跳过”相同的值,而且不会导致覆盖。

注意点:要保证在每次循环“跳过”相同的值时要保证只能跳过一个值,要么b,要么c,不能同时改变。

              其实这里所做的就是将N^2的二重循环用一重循环实现,时间复杂度不精确的表示为O(2N)。

              外面循环a的改变也需要进行“跳过”操作。

具体代码:
class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		
		vector<vector<int>> results = {};
		if (nums.size()<3)return results;
		sort(nums.begin(), nums.end());

		int right;
		int tmp;
		int left=0;

		while (left <=nums.size()-3) {
			right = left + 1;
			int end = nums.size() - 1;
			while(right < end) {
					if ((nums[end] + nums[right] + (nums[left]))==0) {
						vector<int> result = { nums[left],nums[right],nums[end]};
						results.push_back(result);
						tmp = nums[end]; while (end >= right && nums[end] == tmp)end--;
					}
					
					if ((nums[end] + nums[right] + (nums[left]))<0) { tmp = nums[right]; while (right <= end && nums[right] == tmp)right++; }
					
					if((nums[end] + nums[right] + (nums[left]))>0){tmp = nums[end]; while (end >= right && nums[end] == tmp)end--; }

			}
		
			tmp = nums[left];
			while(left <=nums.size()-1 && nums[left]==tmp)left++;
		}

		return results;
	}
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值