3Sum

题目链接:https://leetcode.com/problems/3sum/#/description

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: 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]
]
这题目挺有意思,你要注意到的是例解里可以拼凑出两个[-1,0,1],但是题目要求的是unique triplets,也就是说你要处理重复的解。

处理重复的方法不难,只要sort一下数组,你就可以根据index移动前后的值判断是不是重复解。麻烦点的方法,可以把求出来的所有解扔到set里去重,这种方法省脑但是费时费空间。


难点在于使用三层for循环会超时。看到abc三个元素,自然就想到用三个index去代表它们遍历数组,然而残酷的事实告诉我:不是每个index都配拥有一个for循环。


解题思路:

首先判断读入的数组大小是否够大,如果连两个元素都没有,就不用继续跑的,根本没有满足解。

然后才是正式的流程,对于i,使用一个for循环,但是对于j和k,使用的是从数组两头往中间靠拢的方法,这样算法的时间复杂度就从O(n^3)降到了O(n^2)。

由于是我们已经排过序的有序数组,所以可以根据三个元素的值的和的情况判断index的移动情况:

我们把三个元素按序命名为i,front,back

为了分析情况,我们假设front和back在a,b,c,d,e五个数中移动,其中i+b+d = 0

最开始front 指向a,back指向e,此时若

1) i+a+e<0,则front向右移动,指向b,此时i+b+e>0,back左移指向d,sum = 0,得到结果i,b,d

2) i+a+e>0,则back向左移动,指向d,此时i+a+d<0,front右移指向b,sum = 0,得到结果i,b,d

AC代码:

class Solution {
public:
    vector<vector<int> > threeSum(vector<int>& nums) {
    	if(nums.size() <=2) return {};
        vector<vector<int> > ans;
        sort(nums.begin(),nums.end());
        for(int i = 0; i < nums.size() - 2;)
        {
        	int front = i + 1, back = nums.size() - 1;
        	while (front < back)
        	{
        		int tmp_ans = nums[i] + nums[front] + nums[back];
        		if (tmp_ans == 0)
        		{
        			vector<int> tuple ;
        			tuple.push_back(nums[i]);
        			tuple.push_back(nums[front]);
        			tuple.push_back(nums[back]);
        			ans.push_back(tuple);
        			front ++;
        			back --;
        			while (front < back && nums[front - 1] == nums[front]) front ++;
					while (front < back && nums[back + 1] == nums[back]) back --; 
				}
				else if (tmp_ans < 0)
				{
					front ++;
					while (front < back && nums[front - 1] == nums[front]) front ++;
				}
				else
				{
					back --;
					while (front < back && nums[back + 1] == nums[back]) back --;
				}
			}
			i ++;
			while((i < nums.size()) && nums[i] == nums[i-1]) i++;
		}
		return ans;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值