数据结构与算法-005-数组-三数之和

米斯特程序猿 2021年11月16日 468次浏览

三数之和

  • 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
  • 注意:答案中不可以包含重复的三元组。
  • 题目来自Leetcode

暴力解题

  1. public List<List<Integer>> threeSum(int[] nums) {
  2. // 暴力法,三遍循环,O(n^3),该方式在leetcode执行会超时
  3. // 要求:返回结果不重复
  4. // 先将数据进行一次排序,这样后面处理起来方便
  5. Arrays.sort(nums);
  6. Set<String> distinct=new HashSet<>();
  7. List<List<Integer>> data=new LinkedList<List<Integer>>();
  8. for(int i=0;i<nums.length;i++){
  9. for(int j=i+1;j<nums.length;j++){
  10. for(int n=j+1;n<nums.length;n++){
  11. if((nums[i]+nums[j]+nums[n])==0){
  12. List<Integer> temp=new LinkedList<Integer>();
  13. temp.add(nums[i]);
  14. temp.add(nums[j]);
  15. temp.add(nums[n]);
  16. // 排序是为了方便对数据进行hash,这样就能去重了
  17. // 后排序模式,结果也正确,但是无法通过leetcode测试,因为leetcode 结果是有序的
  18. // Collections.sort(temp);
  19. String tt=temp.toString();
  20. if(distinct.add(tt)){
  21. data.add(temp);
  22. }
  23. }
  24. }
  25. }
  26. }
  27. return data;
  28. }

双指针法,参考

  1. public List<List<Integer>> threeSum(int[] nums) {
  2. // 使用快慢指针法(双指针法)
  3. // 时间复杂度降低为O(n)+O(nlogn)
  4. List<List<Integer>> data=new LinkedList<>();
  5. // 边界条件处理,小于3个元素,则直接返回
  6. if(nums.length<3){
  7. return data;
  8. }
  9. // 等于3个元素,直接判断
  10. if(nums.length==3){
  11. if((nums[0]+nums[1]+nums[2])==0){
  12. List<Integer> temp=new LinkedList<>();
  13. temp.add(nums[0]);
  14. temp.add(nums[1]);
  15. temp.add(nums[2]);
  16. // leetcode 判题需要,所以排下序 ╮(╯▽╰)╭
  17. Collections.sort(temp);
  18. data.add(temp);
  19. return data;
  20. }
  21. }

  22. // 数据做一次排序,方便后续处理,主要是方便去重
  23. Arrays.sort(nums);
  24. for(int i=0;i<nums.length;i++){
  25. // 因为已经排序过了,所以当遇上大于0的数字时,后面的数字加起来是不会等于0的,所以直接返回结果即可
  26. if(nums[i]>0){
  27. return data;
  28. }
  29. // 跳过相同元素
  30. if(i>0 && nums[i]==nums[i-1])
  31. continue;

  32. int left=i+1,right=nums.length-1;
  33. while(left<right){
  34. int ret=nums[i]+nums[left]+nums[right];
  35. if(ret==0){
  36. List<Integer> temp=new LinkedList<>();
  37. temp.add(nums[i]);
  38. temp.add(nums[left]);
  39. temp.add(nums[right]);
  40. data.add(temp);
  41. // 去重
  42. while(left<right&&nums[left]==nums[left+1]){
  43. left++;
  44. }
  45. // 去重
  46. while(left<right&&nums[right]==nums[right-1]){
  47. right--;
  48. }
  49. // 左右移动一位到相同元素的最后一个
  50. left++;
  51. right--;
  52. }else if(ret>0){
  53. // 和大于0,说明右面元素值过大,右指针移动
  54. right--;
  55. }else{
  56. // 和小于0,说明左边元素值过小,左指针移动
  57. left++;
  58. }
  59. }
  60. }
  61. return data;
  62. }