前端刷题路-Day61:在排序数组中查找元素的第一个和最后一个位置(题号34)

516 阅读3分钟

这是我参与更文挑战的第25天,活动详情查看: 更文挑战

组合总和(题号39)

题目

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

示例 2:

输入:candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

提示:

  • 1 <= candidates.length <= 30
  • 1 <= candidates[i] <= 200
  • candidate 中的每个元素都是独一无二的。
  • 1 <= target <= 500

链接

leetcode-cn.com/problems/co…

解释

这题啊,这题是朴实无华。

看到这题的第一反应是用DP来做,可左思右想也想不出合适的DP思路。

为什么用不了DP呢?原因就在于这句话👇:

candidates 中的数字可以无限制重复被选取。

既然都可以无限制被重复选取了,就证明DP是用不了的。

而且题目还有一点小坑,这一点笔者倒是很早就发现了,看官方给的两个示例:

[2,3,6,7]
[2,3,5]

这两个示例都是升序的,再加上题目说的数字是不重复的,很容易让人联想到这是一个没有重复数字的升序数组,结果其实并不是的,升序是不存在的,这里的用例就是凑巧是升序的而已。

不用DP这题应该怎么解呢?很简单——回溯。

用了回溯就很简单了,这里只需要进行两部回溯操作。

在开始介绍解法之前,先想想回溯到定义,笔者认为回溯就是不断尝试所有可能性,遇到合适的结果就记住,直到尝试完所有的可能性位置。

放到这题里,需要尝试的地方只有一个,换成题目里的一句话就是:

candidates 中的数字可以无限制重复被选取。

只要在每次循环的时候再从当前元素开始就好了,当然了,这里有个条件,就是目标值要大于等于当前元素的值,否则明显就超过了,这还尝试啥。

而且如果没有这个条件,回溯会无限进行下去。

在进行回溯的过程中需要记住三个东西:

  1. 当前的数组
  2. 目标和或者剩余的目标值
  3. 当前的位置(index)

每次回溯会有两种情况:

  1. 不进行数字选择

    数组和剩余目标值都不用动 ,直接index + 1即可。

  2. 进行数字选择

    选了数字,目标值就得减去当前数字了,同时数组需要增加一位,index不用动。

说到这里,回溯的写法也就呼之欲出了,推荐自己试试再看下面的答案。

自己的答案

更好的方法(回溯)

话不多说,先看代码👇:

var combinationSum = function(candidates, target) {
  var res = []
  function DFS(arr, index, target) {
    if (index === candidates.length) return
    if (target === 0) return res.push(arr)
    // 不选当前元素,直接下一个元素
    DFS(arr, index + 1, target)
    // 如果条件合适,可以再次选择当前元素
    if (target - candidates[index] >= 0) {
      DFS([...arr, candidates[index]], index, target - candidates[index])
    }
  }
  DFS([], 0, target)
  return res
};

大部分代码都和解释中说的一样,这里可以注意下这行代码👇:

if (index === candidates.length) return

这行代码的意思是如果当前index已经走到头了,超过了数组的长度,那就终止此次回溯,这样写其实也可以👇:

if (!candidates[index]) return

都是一样的道理。

其它的就和解释中说的一样了,官方说可能还有更好的剪枝方法,但笔者并没有想到,翻阅了一些别的答案,好像也没有更好的剪枝方案,如果有同学了解欢迎在评论区留言。



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)

有兴趣的也可以看看我的个人主页👇

Here is RZ