【每日一题】[15. 三数之和]
【每日一题】15. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
提示:
- 3 <= nums.length <= 3000
- -105 <= nums[i] <= 105
解法一:暴力循环O(n^3)
- 排序加三重遍历,并添加重复元素限制
- TLO(Time Limit Out)了
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> ans = new ArrayList<>(); Arrays.sort(nums); var n = nums.length; for(var i = 0; i < n - 2; i++) { if(i > 0 && nums[i] == nums[i-1]) { continue; } for(var j = i + 1; j < n - 1; j++) { if(j > i + 1 && nums[j] == nums[j-1]) { continue; } for(var k = j + 1; k < n; k++) { if(k > j + 1 && nums[k] == nums[k-1]) { continue; } if(nums[i] + nums[j] + nums[k] == 0) { List<Integer> path = new ArrayList<>(); path.add(nums[i]); path.add(nums[j]); path.add(nums[k]); ans.add(path); } } } } return ans; } }
解法二:双指针优化O(n^2)
- 先对数组进行升序排序
- 然后遍历第一个数,则剩下两个数的和要为这个数的负数
- 双指针设置第一个数后面的位置
i+1
和最后一个位置r=n-1
,如果- sum > target,说明和太大,则右指针左移
- sum < target,说明和太小,则左指针右移
- 查找三个数一般都可以使用这种双指针进行优化
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> ans = new ArrayList<>(); Arrays.sort(nums); var n = nums.length; for(var i = 0; i < n; i++) { if(i > 0 && nums[i] == nums[i-1]) { continue; } var target = -nums[i]; var l = i + 1; var r = n - 1; while(l < r) { // System.out.println(i + " " + l + " " + r); var sum = nums[l] + nums[r]; if(sum == target) { List<Integer> path = new ArrayList<>(); path.add(nums[i]); path.add(nums[l]); path.add(nums[r]); ans.add(path); while(l < r && nums[l+1] == nums[l]) { l++; } while(r > l && nums[r-1] == nums[r]) { r--; } l++; r--; } else if(sum > target) { r--; } else { l++; } } } // -4 -1 -1 0 1 2 return ans; } }
解法三:哈希优化
- 同样是使用排序加限定条件防止重复
- 使用map记录元素的value和下标,然后遍历前两个元素,判断最后一个元素的value是否等于前两个的和的负数并下标在前两个之后即可
class Solution { public List<List<Integer>> threeSum(int[] nums) { int n = nums.length; Arrays.sort(nums); HashMap<Integer, Integer> map = new HashMap<>(); List<List<Integer>> ans = new ArrayList<>(); for (int i = 0; i < n; i++) { map.put(nums[i], i); } for (int i = 0; i < n - 1; i++) { if (nums[i] > 0) { return ans; } if(i > 0 && nums[i-1] == nums[i]) { continue; } for (int j = i + 1; j < n; j++) { if(j > i + 1 && nums[j] == nums[j - 1] || nums[i] + nums[j] > 0) { continue; } int sum = -nums[i] - nums[j]; if (map.get(sum) != null && map.get(sum) > j) { List<Integer> dummy = new ArrayList<>(); dummy.add(nums[i]); dummy.add(nums[j]); dummy.add(sum); ans.add(dummy); } } } return ans; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步