这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。
53. 组合 (combinations)
标签
- DFS + 回溯
- 中等
题目
这里不贴题了,leetcode打开就行,题目大意:
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
相关知识
组合问题,可以用回溯法:如果不了解,请移步这篇 回溯思想
基本步骤
- 初始化原始数组
- 还是用老方法 dfs + 回溯,代码几乎和上次一模一样
- 不同之处是因为不能重复排列,所以加一个
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打开就行,题目大意:
给你一个整数数组 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打开就行,题目大意:
给定一个可能包含重复元素的整数数组 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,我看到就通过,暗号对不上不加哈,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧
另外,想找我聊天解愁,交个朋友的也欢迎哈。