模板

如果出现再一个数组中要求求三个数之和等于一个数,或者四个数和等于一个数,那么此时使用hash表会比较繁琐,推荐使用双指针。
失效情况:Map中讲到的两数之和,此时需要返回索引,但是我们此时需要排序之后进行双指针法,所以返回索引会很麻烦,此时就适合使用map的value存储索引。
以下就是模板,可以把0换成任意的数,就可以使用此模板,注意排序问题,和去重问题。

  1. /**
  2. * 双指针+排序
  3. *
  4. * @param nums
  5. * @return
  6. */
  7. public List<List<Integer>> threeSum(int[] nums) {
  8. // 先进行排序
  9. Arrays.sort(nums);
  10. List<List<Integer>> res = new ArrayList<>();
  11. for (int i = 0; i < nums.length; i++) {
  12. // 第一个数都已经大于了0
  13. if (nums[0] > 0) {
  14. return res;
  15. }
  16. // 去重
  17. if (i > 0 && nums[i] == nums[i - 1]) {
  18. continue;
  19. }
  20. int left = i + 1, right = nums.length - 1;
  21. while (left < right) {
  22. int sum = nums[left] + nums[i] + nums[right];
  23. if (sum > 0) {
  24. right--;
  25. } else if (sum < 0) {
  26. left++;
  27. } else {
  28. // 再次去重
  29. while (left < right && nums[left] == nums[left + 1]) left++;
  30. while (left < right && nums[right] == nums[right - 1]) right--;
  31. res.add(Arrays.asList(nums[i],nums[left],nums[right]));
  32. left++;
  33. right--;
  34. }
  35. }
  36. }
  37. return res;
  38. }
  39. }

三数之和

以下例题的详细解析传送🔗

  1. /**
  2. * 双指针法 + 排序
  3. *
  4. * @param nums
  5. * @return
  6. */
  7. public List<List<Integer>> threeSum(int[] nums) {
  8. List<List<Integer>> result = new ArrayList<>();
  9. // 先将数组进行排序
  10. Arrays.sort(nums);
  11. // 循环遍历数组
  12. for (int i = 0; i < nums.length; i++) {
  13. // 排序后如果第一个数大于0,那么一定不可能凑出三元组
  14. if (nums[i] > 0) {
  15. return result;
  16. }
  17. // 错误去重方法,将会漏掉-1,-1,2 这种情况
  18. /*
  19. if (nums[i] == nums[i + 1]) {
  20. continue;
  21. }
  22. */
  23. // 两个数相等时,直接跳过这次判断,达到去重效果
  24. if (i > 0 && nums[i] == nums[i - 1]) {
  25. continue;
  26. }
  27. int left = i + 1, right = nums.length - 1;
  28. while (left < right) {
  29. // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
  30. /*
  31. while (right > left && nums[right] == nums[right - 1]) right--;
  32. while (right > left && nums[left] == nums[left + 1]) left++;
  33. */
  34. int sum = nums[i] + nums[left] + nums[right];
  35. // 大于0即右指针向左移动
  36. if (sum > 0) {
  37. right--;
  38. }
  39. // 小于0即左指针向右移动
  40. else if (sum < 0) {
  41. left++;
  42. }
  43. else{
  44. result.add(Arrays.asList(nums[i], nums[left], nums[right]));
  45. // 去重,去重应该放在最后,放在最前面会漏掉0,0,0
  46. while (right > left && nums[right - 1] == nums[right]) right--;
  47. while (right > left && nums[left + 1] == nums[left]) left++;
  48. // 再继续判断是否有相加为0的数
  49. right--;
  50. left++;
  51. }
  52. }
  53. }
  54. return result;
  55. }

四数之和

  1. /**
  2. * 双指针 + 排序
  3. *
  4. * @param nums
  5. * @param target
  6. * @return
  7. */
  8. public List<List<Integer>> fourSum(int[] nums, int target) {
  9. // 先将数组进行排序
  10. Arrays.sort(nums);
  11. List<List<Integer>> result = new ArrayList<>();
  12. for (int i = 0; i < nums.length; i++) {
  13. // 第一个数都大于target,那就不会有四元组相加等于target,此时不能使用判断,因为target存在负数
  14. // if (i > 0 && nums[i] > target) {
  15. // return result;
  16. // }
  17. // 有重复数据,直接跳过,达到去重效果
  18. if (i > 0 && nums[i] == nums[i - 1]) {
  19. continue;
  20. }
  21. for (int j = i + 1; j < nums.length; j++) {
  22. // 此处不能判断第一个数大于target就返回,因为此时j不是最外层
  23. // if (i > 0 && nums[i] > target) {
  24. // return result;
  25. // }
  26. // 有重复数据,直接跳过,达到去重效果
  27. // 注意此时 j > i + 1 ,不是 j > i ,否则漏掉2,2,2,2,2 8
  28. if (j > i + 1 && nums[j] == nums[j - 1]) {
  29. continue;
  30. }
  31. int left = j + 1, right = nums.length - 1;
  32. while (left < right) {
  33. int sum = nums[i] + nums[j] + nums[left] + nums[right];
  34. if (sum > target) {
  35. right--;
  36. } else if (sum < target) {
  37. left++;
  38. } else {
  39. result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
  40. while (left < right && nums[right] == nums[right - 1]) right--;
  41. while (left < right && nums[left] == nums[left + 1]) left++;
  42. left++;
  43. right--;
  44. }
  45. }
  46. }
  47. }
  48. return result;
  49. }