LeetCode笔记——15三数之和

题目:

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

思路:提交的代码是在网上百度的大神们的代码。基本的思想是对先对数组进行排序,然后使用三个指针,对的数组中的每一个元素依次检查该元素的下一个元素和数组最后的元素是否相加为0;若不是移动指针的位置,若是,将其保存在集合中,移动指针,同时注意跳过相同元素。

执行最快的代码:

最快的代码有些看不懂。。。。。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
      if (nums.length < 3)
        return Collections.emptyList();
      List<List<Integer>> res = new ArrayList<>();
      int minValue = Integer.MAX_VALUE;
      int maxValue = Integer.MIN_VALUE;
      int negSize = 0;
      int posSize = 0;
      int zeroSize = 0;
      for (int v : nums) {
        if (v < minValue)
          minValue = v;
        if (v > maxValue)
          maxValue = v;
        if (v > 0)
          posSize++;
        else if (v < 0)
          negSize++;
        else
          zeroSize++;
      }
      if (zeroSize >= 3)
        res.add(Arrays.asList(0, 0, 0));
      if (negSize == 0 || posSize == 0)
        return res;
      if (minValue * 2 + maxValue > 0)
        maxValue = -minValue * 2;
      else if (maxValue * 2 + minValue < 0)
        minValue = -maxValue * 2;

      int[] map = new int[maxValue - minValue + 1];
      int[] negs = new int[negSize];
      int[] poses = new int[posSize];
      negSize = 0;
      posSize = 0;
      for (int v : nums) {
        if (v >= minValue && v <= maxValue) {
          if (map[v - minValue]++ == 0) {
            if (v > 0)
              poses[posSize++] = v;
            else if (v < 0)
              negs[negSize++] = v;
          }
        }
      }
      Arrays.sort(poses, 0, posSize);
      Arrays.sort(negs, 0, negSize);
      int basej = 0;
      for (int i = negSize - 1; i >= 0; i--) {
        int nv = negs[i];
        int minp = (-nv) >>> 1;
        while (basej < posSize && poses[basej] < minp)
          basej++;
        for (int j = basej; j < posSize; j++) {
          int pv = poses[j];
          int cv = 0 - nv - pv;
          if (cv >= nv && cv <= pv) {
            if (cv == nv) {
              if (map[nv - minValue] > 1)
                res.add(Arrays.asList(nv, nv, pv));
            } else if (cv == pv) {
              if (map[pv - minValue] > 1)
                res.add(Arrays.asList(nv, pv, pv));
            } else {
              if (map[cv - minValue] > 0)
                res.add(Arrays.asList(nv, cv, pv));
            }
          } else if (cv < nv)
            break;
        }
      }
      return res;
    }
}

代码:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new LinkedList<>();

        if (nums != null && nums.length > 2) {
            // 先对数组进行排序
            Arrays.sort(nums);
            // i表示假设取第i个数作为结果
            for (int i = 0; i < nums.length - 2; ) {
                // 第二个数可能的起始位置
                int j = i + 1;
                // 第三个数可能是结束位置
                int k = nums.length - 1;

扫描二维码关注公众号,回复: 3481435 查看本文章

                while (j < k) {
                    // 如果找到满足条件的解
                    if (nums[j] + nums[k] == -nums[i]) {
                        // 将结果添加到结果含集中
                        List<Integer> list = new ArrayList<>(3);
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(nums[k]);
                        result.add(list);

                        // 移动到下一个位置,找下一组解
                        k--;
                        j++;

                        // 从左向右找第一个与之前处理的数不同的数的下标
                        while (j < k && nums[j] == nums[j - 1]) {
                            j++;
                        }
                        // 从右向左找第一个与之前处理的数不同的数的下标
                        while (j < k && nums[k] == nums[k + 1]) {
                            k--;
                        }
                    }
                    // 和大于0
                    else if (nums[j] + nums[k] > -nums[i]) {
                        k--;
                        // 从右向左找第一个与之前处理的数不同的数的下标
                        while (j < k && nums[k] == nums[k + 1]) {
                            k--;
                        }
                    }
                    // 和小于0
                    else {
                        j++;
                        // 从左向右找第一个与之前处理的数不同的数的下标
                        while (j < k && nums[j] == nums[j - 1]) {
                            j++;
                        }
                        }
                }

                // 指向下一个要处理的数
                i++;
                // 从左向右找第一个与之前处理的数不同的数的下标
                while (i < nums.length - 2 && nums[i] == nums[i - 1]) {
                    i++;
                }
            }
        }

        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/chenxy132/article/details/82720690