LeetCode 15.三数之和


三数之和


思路:排序+双指针

时间复杂度: O ( n 2 ) O(n^2) O(n2),空间复杂度:O(logn)

分析:
  1. 首先,需要解决的问题是无重复,对于,这个问题我们可以用排序来解决,而sort的时间复杂度为nlogn,如此,我们每次枚举的n1, n2, n3就满足n1 <= n2 <= n3
  2. 其次,如果对nums排序之后的算法的时间复杂度依然是 O ( n 3 ) O(n^3) O(n3)的,注意到,第一层for循环枚举0~n-1,而第二、三层循环实际上是并列关系,因为nums是有序的,所以可以采用双指针的思想,即,第二、三层循环分别用从小到大和从大到小的指针替代。
  • 伪代码
nums.sort()
for first = 0 ... n-1
	if first == 0 or nums[first] != nums[first-1] then
		// 第三重循环对应的指针
		third = n-1
		for second = first+1 ... n-1
			if second == first+1 or nums[second] != nums[second-1] then 
			// 向左移动指针,直到 a+b+c 不大于 0
			while nums[first]+nums[second]+nums[third] > 0
				third = third-1
			// 判断是否有 a+b+c = 0
			check(first, second, third)
写法一:
class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		int n = nums.size();
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;

		// 枚举 a
		for (int i = 0; i < n; ++i) {
			// 不重复
			if (i && nums[i] == nums[i]) continue;
			// 双指针:j、k
			// 先固定右指针
			int k = n-1;
			int target = -nums[i];
			for (int j = i+1; j < n; ++j) {
				// 保证不枚举到重复的元素
				if (j > i+1 && nums[j] == nums[j-1]) continue;
				// 移动右指针的情况:左指针已经枚举到右指针了且此时 nums[j] + nums[k] 太大
				while (j > k && nums[j] + nums[k] > target) --k;
				/*
					思考:为啥不考虑,nums[j] + nums[k] < target 的情况呢?
					--> 要知道:k 是右指针一定是当前的最大值,所以在固定 k 的情况下
					枚举的 nums[j] + nums[k] 是从小到大(下标j的值逐渐增加),
					所以枚举一遍之后,如果没有出现等于target或者大于target的情况,
					可以直接break, 那必然下次枚举时,下标 j 的值会变大。
				*/
				if (j == k) break;
				if (nums[j] + nums[k] == target)
					res.push_back({nums[i], nums[j], nums[k]});
			}
		}
		return res;
	}
}
写法二:
class Solution {
public:
	vector<vector<int>> threeSum(vector<int>& nums) {
		int n = nums.size();
		sort(nums.begin(), nums.end());
		vector<vector<int>> res;
		for (int i = 0; i < n-2; ++i) {
			int x = nums[i];
			if (i && x == nums[i-1]) continue;
			if (x + nums[i+1] + nums[i+2] > 0) break;
			if (x + nums[n-1] + nums[n-2] < 0) continue;
			int j = i + 1, k = n - 1;
			while (j < k) {
				int s = x + nums[j] + nums[k];
				if (s > 0) --k;
				else if (s < 0) ++j;
				else {
					res.push_back({x, nums[j], nums[k]});
					// 避免重复枚举
					for (++j; j < k && nums[j] == nums[j-1]; ++j);
					for (--k; j < k && nums[k] == nums[k+1]; --k);
				}
			}  
		}
		return res;
	}
};

😘😘😘😘😘😘😘😘😘

😘😘😘😘😘😘😘😘😘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值