前端算法面试必刷题系列[31]

342 阅读2分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

53. 组合 (combinations)

标签

  • DFS + 回溯
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

相关知识

组合问题,可以用回溯法:如果不了解,请移步这篇 回溯思想

基本步骤

  1. 初始化原始数组
  2. 还是用老方法 dfs + 回溯,代码几乎和上次一模一样
  3. 不同之处是因为不能重复排列,所以加一个 startIdx 限制下就行

写法实现

var combine = function(n, k) {
  let [res, curUsed] = [[], {}]
  // 先把初始选择的数组弄出来 n = 4 => nArray = [1, 2, 3, 4]
  let nArray = new Array(n).fill(0).map((it, index) => index + 1)
  // DFS + 回溯
  let dfs = (startIdx, curPath) => {
    if (curPath.length === k) {
      res.push(curPath.slice())
      return
    }
    for(let i = 0, len = nArray.length; i < len; i++){
      if (curUsed[i] || i < startIdx) {
        continue;
      }
      curPath.push(nArray[i])
      curUsed[i] = true
      dfs(i + 1, curPath)
      curPath.pop()
      curUsed[i] = false
    }
  }
  dfs(0, [])
  return res
};

let n = 4, k = 2
console.log(combine(n, k))

54. 子集 (subsets)

标签

  • DFS + 回溯
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给你一个整数数组 nums ,数组中的元素互不相同 。返回该数组所有可能的子集(幂集)。

解集不能包含重复的子集。你可以按任意顺序返回解集。

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

基本步骤

我觉得你看完上面几个问题并理解了,这个问题步骤你心知肚明。不赘述,代码几乎同上。

写法实现

var subsets = function(nums) {
  let [res, curUsed] = [[], {}]
  let dfs = (startIdx, curPath) => {
    res.push(curPath.slice())

    for(var i = 0, len = nums.length; i < len; i++){
      if (curUsed[i] || i < startIdx) {
        continue;
      }
      curPath.push(nums[i])
      curUsed[i] = true
      dfs(i + 1, curPath)
      curPath.pop()
      curUsed[i] = false
    }
  }
  dfs(0, [])
  return res
};

let nums = [1,2,3]
console.log(subsets(nums))

55. 子集 II (subsets-ii)

标签

  • DFS + 回溯
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

解集不能包含重复的子集。你可以按任意顺序返回解集。

输入: [1,2,2]
输出:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

基本步骤

上一个问题的升级版,有重复元素。大体思路相同,仔细看下面注释进行微细变化。

写法实现

var subsetsWithDup = function(nums) {
  let [res, curUsed] = [[], {}]
  // 先排序
  nums = nums.sort((a, b) => a - b)
  let dfs = (startIdx, curPath) => {
    res.push(curPath.slice())

    for(var i = 0, len = nums.length; i < len; i++){
      if (curUsed[i] || i < startIdx) {
        continue;
      }
      // 当前值用过了 或
      // 当前值等于前一个值: 两种情况:
        // 1 nums[i-1] 没用过 说明回溯到了同一层 此时接着用num[i] 则会与 同层用num[i-1] 重复
        // 2 nums[i-1] 用过了 说明此时在num[i-1]的下一层 相等不会重复
      if (i > 0 && nums[i] === nums[i-1] && curUsed[i-1] === false) {
        continue
      }
      curPath.push(nums[i])
      curUsed[i] = true
      dfs(i + 1, curPath)
      curPath.pop()
      curUsed[i] = false
    }
  }
  dfs(0, [])
  return res
};

let nums = [1,2,2]
console.log(subsetsWithDup(nums))

这三个问题下来,我觉得你对 DFS + 回溯类问题游刃有余了!

另外向大家着重推荐下这位大哥的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

另外,想找我聊天解愁交个朋友的也欢迎哈。

参考