📑 题目:16. 最接近的三数之和

🚀 本题 LeetCode 传送门

题目大意

给定一个数组,要求在这个数组中找出 3 个数之和离 target 最近。

解题思路

这一题看似和第 15 题和第 18 题很像,都是求 3 或者 4 个数之和的问题,但是这一题的做法和 15,18 题完全不同。

这一题的解法是用两个指针夹逼的方法。先对数组进行排序,i 从头开始往后面扫。这里同样需要注意数组中存在多个重复数字的问题。具体处理方法很多,可以用 map 计数去重。这里笔者简单的处理,i 在循环的时候和前一个数进行比较,如果相等,i 继续往后移,直到移到下一个和前一个数字不同的位置。j,k 两个指针开始一前一后夹逼。j 为 i 的下一个数字,k 为数组最后一个数字,由于经过排序,所以 k 的数字最大。j 往后移动,k 往前移动,逐渐夹逼出最接近 target 的值。

这道题还可以用暴力解法,三层循环找到距离 target 最近的组合。具体见代码。

代码

  1. package leetcode
  2. import (
  3. ""math""
  4. ""sort""
  5. )
  6. // 解法一 O(n^2)
  7. func threeSumClosest(nums []int, target int) int {
  8. n, res, diff := len(nums), 0, math.MaxInt32
  9. if n > 2 {
  10. sort.Ints(nums)
  11. for i := 0; i < n-2; i++ {
  12. if i > 0 && nums[i] == nums[i-1] {
  13. continue
  14. }
  15. for j, k := i+1, n-1; j < k; {
  16. sum := nums[i] + nums[j] + nums[k]
  17. if abs(sum-target) < diff {
  18. res, diff = sum, abs(sum-target)
  19. }
  20. if sum == target {
  21. return res
  22. } else if sum > target {
  23. k--
  24. } else {
  25. j++
  26. }
  27. }
  28. }
  29. }
  30. return res
  31. }
  32. // 解法二 暴力解法 O(n^3)
  33. func threeSumClosest1(nums []int, target int) int {
  34. res, difference := 0, math.MaxInt16
  35. for i := 0; i < len(nums); i++ {
  36. for j := i + 1; j < len(nums); j++ {
  37. for k := j + 1; k < len(nums); k++ {
  38. if abs(nums[i]+nums[j]+nums[k]-target) < difference {
  39. difference = abs(nums[i] + nums[j] + nums[k] - target)
  40. res = nums[i] + nums[j] + nums[k]
  41. }
  42. }
  43. }
  44. }
  45. return res
  46. }
  47. func abs(a int) int {
  48. if a > 0 {
  49. return a
  50. }
  51. return -a
  52. }