Last Commit: 2024-01-06 17:50:27

views:

15. 3Sum

source: https://leetcode.com/problems/3sum/

Question

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

暴力法

这道题可以粗暴的用三个loop去比较,然后筛选distinct的tuple. 很明显,时间复杂度是O(n3), 在leetcode上是会超标的。

var threeSum = function (nums) {
  const ret = [];
  for (let i1 = 0; i1 < nums.length; i1++) {
    for (let i2 = 0; i2 < nums.length; i2++) {
      if (i1 === i2) continue;
      for (let i3 = 0; i3 < nums.length; i3++) {
        if (i2 === i3 || i1 === i3) continue;
        const a = nums[i1];
        const b = nums[i2];
        const c = nums[i3];
        if (a + b + c === 0) {
          const v = [a, b, c].sort((a, b) => a - b).join(",");
          if (!ret.includes(v)) ret.push(v);
        }
      }
    }
  }
  return ret.map((v) => v.split(","));
};

优化思路

由于三个元素是不重复的,可以得到一个不等式:

  • a <= b <= c

且有多个loop, 很容易想到用左右指针的思路去做优化。

var threeSum = function (nums) {
  const ret = [];
  nums.sort((a, b) => a - b);
  for (let i = 0; i < nums.length; i++) {
    let p1 = i + 1;
    let p2 = nums.length - 1;
    while (p1 < p2) {
      const v = nums[i] + nums[p1] + nums[p2];
      if (v > 0) {
        p2--;
      } else if (v < 0) {
        p1++;
      } else {
        const s = `${[nums[i], nums[p1], nums[p2]]}`;
        if (!ret.includes(s)) ret.push(s);
        p1++;
        p2--;
      }
    }
  }
  return ret.map((v) => v.split(","));
};

优化不判断重复值:

var threeSum = function (nums) {
  const ret = [];
  nums.sort((a, b) => a - b);
  for (let i1 = 0; i1 < nums.length; i1++) {
    const a = nums[i1];
    if (a > 0) return ret;
    if (i1 > 0 && a === nums[i1 - 1]) continue;
    let p1 = i1 + 1;
    let p2 = nums.length - 1;
    while (p1 < p2) {
      const v = a + nums[p1] + nums[p2];
      if (v > 0) {
        p2 -= 1;
      } else if (v < 0) {
        p1 += 1;
      } else {
        ret.push([a, nums[p1], nums[p2]]);
        while (p1 < p2 && nums[p1] === nums[p1 + 1]) p1 += 1;
        while (p1 < p2 && nums[p2] === nums[p2 - 1]) p2 -= 1;
        p1 += 1;
        p2 -= 1;
      }
    }
  }
  return ret;
};

总结

对于排序数组,多个loop,可以忘双指针这个思路去优化。