0
点赞
收藏
分享

微信扫一扫

跟着代码随想录练算法之——回溯算法(js)

修炼之士 2022-05-03 阅读 106

回溯

77. 组合

/**
 * @param {number} n
 * @param {number} k
 * @return {number[][]}
 */
var combine = function(n, k) {
    let ans = []
    let each = []
    const backtracking = (n, k, start) => {
        if(each.length === k){
            ans.push([...each])
            return
        }
        for(let i = start; i <= n - (k - each.length) + 1; i++ ){
            each.push(i)
            backtracking(n, k, i + 1)
            each.pop()
        }
    }
    backtracking(n, k, 1)
    return ans
};

216. 组合总和 III

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    let each = []
    let ans = []
    const backtracking = (sum, start, k, n) => {
        if(sum > n) return
        if(each.length === k){
            if(sum === n){
                ans.push([...each])
            }
            return
        }
        for(let i = start; i <= 9 - (k - each.length) + 1; i++){
            each.push(i)
            backtracking(sum + i, i + 1, k, n)
            each.pop()
        }
    }
    backtracking(0, 1, k, n)
    return ans
};

17. 电话号码的字母组合

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
    if(digits.length === 0) return []
    let ans = []
    let each = []
    let obj = {
        2: 'abc',
        3: 'def',
        4: 'ghi',
        5: 'jkl',
        6: 'mno',
        7: 'pqrs',
        8: 'tuv',
        9: 'wxyz'
    }
    const backtracking = (start, digits) => {
        if(each.length === digits.length){
            ans.push(each.join(''))
            return
        }
        for(let i = 0; i < obj[digits[start]].length; i++){
            each.push(obj[digits[start]][i])
            backtracking(start + 1, digits)
            each.pop()
        }
    }
    backtracking(0,digits)
    return ans
};

39. 组合总和

  • 因为每个元素的数量没有限制,也就是下一层中可选择的位置是可以包括这次的位置。
  • 下一层的 start 可以从i开始,如果要求最多只能出现一次那么只能从 i+1 开始
/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function(candidates, target) {
    let ans = []
    let each = []
    const backtracking = (nowSum, start) => {
        if(nowSum > target) return
        if(nowSum === target){
            ans.push([...each])
            return
        }
        for(let i = start; i < candidates.length; i++){
            each.push(candidates[i])
            backtracking(nowSum + candidates[i], i)
            each.pop()
        }
    }
    backtracking(0,0)
    return ans
};

40. 组合总和 Ⅱ

与上面这一题的不同点:

  • candidates 中的每个数字在每个组合中只能使用一次

    下一层的取数就要从 i +1 开始

  • 数组candidates的元素是有重复的

    横向的 for 循环需要去重,在这之前要保证candidates 中的数字是有序的,所以需要先排序,当 i > start && candidates[i] === candidates[i - 1] 直接考虑下一个,跳过

  • 剪枝: 当前元素加上后大于 target 跳过

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
    let ans = []
    let each = []
    const backtracking = (start, nowSum) => {
        if(nowSum === target){
            ans.push([...each])
            return
        }
        for(let i = start; i < candidates.length; i++){
            if(nowSum + candidates[i] > target) continue
            if(i > 0 && i > start && candidates[i] === candidates[i - 1]) continue
            each.push(candidates[i])
            backtracking(i + 1, nowSum + candidates[i])
            each.pop()
        }
    }
    candidates.sort((a, b ) => a - b)
    backtracking(0, 0)
    return ans
};

131. 分割回文串

  • i 为切割的地方,s[start~i]为切割下来的子串,先判断子串是否符合回文,不符合就跳过,符合就放在each数组中,然后继续寻找下一个切割位置
  • 递归结束的条件为start已经到了字符串s的末尾
  • 判断回文字符串:使用双指针,一个从前到后,一个从后到前,遇到第一个不相等的字符就直接返回 false
/**
 * @param {string} s
 * @return {string[][]}
 */
const isHuiWen = (s, start, end) => {
    let i = start
    let j = end
    while(i < j){
        if(s[i] !== s[j]) return false
        i ++
        j --
    }
    return true
}
var partition = function(s) {
    let ans = []
    let each = []
    const backtracking = (start) => {
        if(start >= s.length){
            ans.push([...each])
            return
        }
        for(let i = start; i < s.length ; i++){
            if( isHuiWen(s, start, i) === false) continue
            each.push(s.slice(start, i + 1))
            backtracking(i + 1)
            each.pop()
        }
    }
    backtracking(0)
    return ans
};

93. 复原 IP 地址

/**
 * @param {string} s
 * @return {string[]}
 */
var restoreIpAddresses = function(s) {
    if(s.length <= 3) return []
    let ans = []
    let each = []
    const judge = (str) => {
        if(str.length === 0 || +str > 255 || (str.length >= 2 && str[0] == 0) )
            return false
        return true
    }
    const backtracking = (start, pointNum) => {
        if(pointNum === 3){
            if(judge(s.slice(start,s.length))){
                ans.push(each.join('.') + '.' +  s.slice(start,s.length))
            }
            return
        }
        for(let i = start; i < s.length; i++){
            if(s.slice(start, i + 1).length > 3) break
            if( !judge(s.slice(start, i + 1)))
                continue
            each.push(s.slice(start, i + 1))
            backtracking(i + 1, pointNum + 1)
            each.pop()
        }
    }
    
    backtracking(0, 0)
    return ans
};

491. 递增的子序列

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var findSubsequences = function(nums) {
    let ans = []
    let each = []
    const backtracking = (start) => {
        if(each.length > 1){
            ans.push([...each])
        }
        
        let map = new Array(201)
        map.fill(0)
        for(let i = start; i < nums.length; i++ ){
            if(nums[i] < each[each.length - 1] || map[nums[i] + 100] === 1) continue
            map[nums[i] + 100] = 1
            each.push(nums[i])
            backtracking(i + 1)
            each.pop()
        }
    }
    backtracking(0)
    return ans
};

46. 全排列

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    let ans = []
    let each = []
    let used = new Array(21)
    used.fill(0)
    const backtracking = () => {
        if(each.length === nums.length){
            ans.push([...each])
            return
        }
        for(let i = 0; i < nums.length; i++){
            if(used[nums[i] + 10]) continue
            used[nums[i] + 10] = 1
            each.push(nums[i])
            backtracking()
            used[nums[i] + 10] = 0
            each.pop()
        }
    }
    backtracking()
    return ans
};

47. 全排列 Ⅱ

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
    let ans = []
    let each = []
    let used = new Array(10)
    used.fill(0)
    const backtracking = () => {
        if(each.length === nums.length){
            ans.push([...each])
            return
        }
        for(let i = 0; i < nums.length; i++){
            if(used[i] || (i > 0 && nums[i] === nums[i-1] && used[i-1]))
                continue
            each.push(nums[i])
            used[i] = 1
            backtracking()
            used[i] = 0
            each.pop()
        }
    }
    nums.sort((a,b) => a - b)
    backtracking()
    return ans
};

332. 重新安排行程

/**
 * @param {string[][]} tickets
 * @return {string[]}
 */
var findItinerary = function(tickets) {
    let ans = ['JFK']
    let obj = {}
    // 将出发到达的关系储存在 obj 里
    for (ticket of tickets){
        const [from, to] = ticket
        if( !obj[from] ){
            obj[from] = []
        }
        obj[from].push(to)
    }
    // 将到达地点排序
    for (city in obj){
        obj[city].sort()
    }
    const backtracking = () => {
        if(ans.length === tickets.length + 1){
            return true
        }
        
        if( !obj[ans[ans.length - 1]] || !obj[ans[ans.length - 1]].length)
            return false
        for(let i = 0; i < obj[ans[ans.length - 1]].length; i++){
            let city = obj[ans[ans.length - 1]][i]
            obj[ans[ans.length - 1]].splice(i,1)
            ans.push(city)
            if( backtracking() ) return true
            ans.pop()
            obj[ans[ans.length - 1]].splice(i,0,city)
        }
    }
    backtracking()
    return ans
};

51. N 皇后

/**
 * @param {number} n
 * @return {string[][]}
 */
var solveNQueens = function(n) {
    let ans = []
    let each = []
    const isValid = (row, col) => {
        // 列
        for(let i = 0; i < row; i++)
            if(each[i][col] === 'Q') return false
        // 斜对角线
        for(let i = row - 1,j = col - 1; i >= 0 && j >= 0; i--, j--)
            if(each[i][j] === 'Q') return false
        // 对角线
        for(let i = row - 1, j = col + 1; i >= 0 && j <n ; i --, j ++)
            if(each[i][j] === 'Q') return false
        return true
        
    }
    const backtracking = (row) => {
        if(row === n){
            ans.push([...each])
            return
        }
        let col = new Array(n)
        col.fill('.')
        for(let i = 0; i < n; i++){
            if( !isValid(row, i) ) continue
            col.splice(i, 1, 'Q')
            each.push(col.join(''))
            backtracking(row + 1)
            each.pop()
            col.splice(i, 1, '.')
        }
    }
    backtracking(0)
    return ans
};

37. 解数独

/**
 * @param {character[][]} board
 * @return {void} Do not return anything, modify board in-place instead.
 */
var solveSudoku = function(board) {
    const isValid = (row, col, k) => {
        for(let i = 0; i < 9; i++){
            if(board[row][i] === k) return false
            if(board[i][col] === k) return false
        }
        let startI = Math.floor(row/3)*3
        let startJ = Math.floor(col/3)*3
        for(let i = startI; i < startI + 3; i++){
            for(let j = startJ; j < startJ + 3; j++){
                if(board[i][j] == k) return false
            }
        }
        return true
        
    }
    const backtracking = () => {
        for(let i = 0; i < board.length; i++){
            for(let j = 0; j < board[0].length; j++){
                if(board[i][j] !== '.') continue
                for(let k = 1; k <= 9; k++){
                    let str = k.toString()
                    if(isValid(i,j,str)){
                        board[i][j] = str
                        if( backtracking() ) return true
                        board[i][j] = '.'
                    }
                }
                return false
            }
        }
        return true
    }
    backtracking()
    return board
};
举报

相关推荐

0 条评论