LeetCode016接近三数之和(相关话题:双指针)

题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

解题思路:

这个问题和Leetcode 15:三数之和类似。我们首先想到的是通过双指针的方法来解这个问题。我们先要对nums排序,接着建立l和r两个指针,然后我们遍历nums我们要将left=i+1、right=len(nums)-1这样初始化,因为我们希望在[l:r]中进行寻找操作。计算sum=nums[i]+nums[left]+nums[right]和target的差是多少,并且我们要记录下来,最后取最小的差对应的sum作为结果。当left<right的时候,我们就要对窗口进行缩放操作。如果sum<target的话,我们就要将left++,以寻找更大的sum;否则的话,我们将right--,以寻找更小的sum。当本次操作结束后,我们就要进入下一轮循环

代码示例:

// 定义了一个名为LeetCode016接近三数之和的object
object LeetCode016接近三数之和 {

  // 定义了一个函数,返回三个元素和最接近目标值的元素和
  def threeSumClosest(nums: Array[Int], target: Int): Int = {
    // 对输入数组进行排序
    val sortArr = nums.sorted
    // 初始化最接近的差值为最大整数
    var closeResult = Int.MaxValue
    // 初始化临时差值
    var tempResult = 0
    // 初始化答案结果
    var ansResult = 0

    // 遍历数组中的元素,直到倒数第三个元素
    for (i <- 0 until sortArr.length - 2) {
      // 初始化左端点
      var left = i + 1
      // 初始化右端点
      var right = sortArr.length - 1
      // 当左端点小于右端点时,执行循环
      while (left < right) {

        // 计算三数之和
        var arrSum = sortArr(i) + sortArr(left) + sortArr(right)
        // 判断三数之和与目标值的关系
        arrSum match {
          // 如果三数之和小于目标值
          case sum if sum < target => { 
            // 计算目标值与三数之和的差值
            tempResult = target - arrSum; 
            // 左端点向右移动一个位置
            left += 1; 
            // 如果当前差值小于最接近的差值,则更新最接近的差值和答案结果
            if (tempResult < closeResult) { 
              ansResult = arrSum; 
              closeResult = tempResult 
            } 
          }
          // 如果三数之和大于目标值
          case sum if sum > target => { 
            // 计算三数之和与目标值的差值
            tempResult = arrSum - target; 
            // 右端点向左移动一个位置
            right -= 1; 
            // 如果当前差值小于最接近的差值,则更新最接近的差值和答案结果
            if (tempResult < closeResult) { 
              ansResult = arrSum; 
              closeResult = tempResult 
            } 
          }
          // 如果三数之和等于目标值,直接返回三数之和
          case sum if sum == target => return sum
        }

      }
    }
    // 返回答案结果
    return ansResult
  }
}

我们实际上可一对上面这个问题进行剪枝操作。我们首先将nums排序,然后遍历nums中的每个元素num。我们判断nums中最大的两个数加上num后是不是小于target,如果是的话,此时我们没有办法找比这三个更小的和了,我们就要建立一个result数组,将它们的和加入。 我们判断nums中最小的两个数加上num后是不是大于target,如果是的话,此时我们没有办法找比这三个更大的和了,我们就要将它们的和加入到result中。上述这两步操作是剪枝操作。 然后对于其他的情况,我们再按照之前的思路处理即可,但是此时我们直接将和加入result中,而没有对最小距离单独处理。 最后我们只要取和target最近的值即可(将此策略添加到sort函数中)

def threeSumClosest2(nums: Array[Int], target: Int): Int = {
 
    val sortArr = nums.sorted
    var closeResult = Int.MaxValue
    var tempResult = 0
    var ansResult = 0
=
    for (i <- 0 until sortArr.length - 2) {
      var left = i + 1
      var right = sortArr.length - 1
 
     var leftSum = sortArr(left) +sortArr(left + 1) +  sortArr(i)
     var rightSum =  sortArr(right) + sortArr(right - 1) + sortArr(i)
      
     if  (leftSum > target)
        if (tempResult < closeResult) { ansResult = leftSum; closeResult = tempResult } 
      else if (rightSum < target)
        if (tempResult < closeResult) { ansResult = rightSum; closeResult = tempResult } 
     
     
      while (left < right) {
       
        var arrSum = sortArr(i) + sortArr(left) + sortArr(right)
        arrSum match {
          case sum if sum < target => { tempResult = target - arrSum; left += 1; if (tempResult < closeResult) { ansResult = arrSum; closeResult = tempResult } }
          case sum if sum > target => { tempResult = arrSum - target; right -= 1; if (tempResult < closeResult) { ansResult = arrSum; closeResult = tempResult } }
          case sum if sum == target => return sum
        }

      }
    }
    return ansResult
  }
  
  def main(args: Array[String]) {
    var target = 1
    var nums = Array(-1, 2, 1, -4)
    println(threeSumClosest2(nums, target));
  }

参考文章

LeetCode015之三数之和(相关话题:双指针拓展)_击水三千里的博客-CSDN博客

LeetCode018之四数之和(相关话题:双指针)-CSDN博客 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据与算法架构提升之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值