Leetcode15. 三数之和

本文详细解析了LeetCode上的经典问题“三数之和”,提供了排序加双指针算法的解决方案,并附带了Scala和Java代码实现,帮助读者理解如何寻找数组中所有满足条件的不重复三元组。

Leetcode15. 三数之和

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

给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

题解:
排序+双指针
1.给数组按照升序排序;
2.排序后固定一个数 nums[i]nums[i]nums[i]

  • 2.1.如果nums[i]nums[i]nums[i]大于 0,则三数之和必然无法等于 000,结束循环;
  • 2.2.如果 nums[i]nums[i]nums[i]== nums[i−1]nums[i-1]nums[i1],则说明该数字重复,会导致结果重复,所以跳过本次循环;
  • 2.3.使用左右指针指向 nums[i]nums[i]nums[i]后面的两端,数字分别为 nums[j]nums[j]nums[j]nums[k]nums[k]nums[k],计算三个数的和 sumsumsum 判断是否满足为 000,满足则添加进结果集;
      2.3.1.当 sum==0sum == 0sum==0 时,nums[j]==nums[j+1]nums[j] == nums[j+1]nums[j]==nums[j+1]则会导致结果重复,应该跳过,j=j+1
      2.3.2当 sum==0sum == 0sum==0 时,nums[k]==nums[k−1]nums[k] == nums[k−1]nums[k]==nums[k1] 则会导致结果重复,应该跳过,k = k-1
  • 2.4.如果sum>0sum>0sum>0,则将后一位往前移动,即:k=k−1k = k-1k=k1
  • 2.5.如果sum<0sum<0sum<0,则将前一位往后移动,即:j=j+1j = j+1j=j+1

scala代码:

 /**
    *
    * @param nums
    * @return
    */
  def threeSum(nums: Array[Int]): List[List[Int]] = {
    if (nums.length < 3) {
      null
    } else {
      val list = new ListBuffer[ListBuffer[Int]]()
      val nums1 = nums.sorted
      var flag = true
      for (i <- 0 until nums1.length; if (flag)) {
        if (nums1(i) > 0) {
          flag = false
        }
        breakable {
          //如果当前的值和上一个值相同,跳出本次循环,去重
          if (i > 0 && nums1(i) == nums1(i - 1)) {
            break()
          }
          //双指针j,k
          var j = i + 1
          var k = nums1.length - 1
          val target = -nums1(i)
          while (j < k) {
            if (nums1(j) + nums1(k) == target) {
              val curr = new ListBuffer[Int]()
              curr.append(nums1(i))
              curr.append(nums1(j))
              curr.append(nums1(k))
              list.append(curr)

              //当左右两个值相等,去重
              while (j < k && nums1(j) == nums1(j + 1)) j = j + 1
              while (k > j && nums1(k) == nums1(k - 1)) k = k - 1
              k = k - 1
              j = j + 1

            } else if (nums1(j) + nums1(k) > target) {
              k = k - 1
            } else {
              j = j + 1
            }
          }
        }
      }
      val result: List[List[Int]] = list.map(_.toList).toList
      result
    }
  }

java代码:

  public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums.length < 3) return res;
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] > 0) break;
            //因为进行左边重复值判断,避免i越界,加上i>0判断,同时跳出本次循环保证去重
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            List<Integer> list = new ArrayList<>();
            int j = i + 1;
            int k = nums.length - 1;
            int sum = nums[i] + nums[j] + nums[k];
            while (j < k) {
                if (sum > 0) {
                    k--;
                } else if (sum < 0) {
                    j++;
                } else {
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    res.add(list);

                    //通过左边 和右边去重,获取下一个可能出现的滑动窗口
                    while (j < k && nums[j] == nums[j + 1]) j++;
                    while (j < k && nums[k] == nums[k - 1]) k--;
                    j++;
                    k--;
                }
            }
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值