leetcode 之 Search (BFS/DFS)(搜索/回溯)

143 阅读1分钟

Search (BFS/DFS)(搜索/回溯)

主要是利用递归实现

分为下面几种

  1. 组合
  2. 子集
  3. 切割
  4. 排列

17. 电话号码的字母组合

17. 电话号码的字母组合

/**
 * @param {string} digits
 * @return {string[]}
 */
var letterCombinations = function(digits) {
    if (digits.length == 0) return [];
    const map = { '2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz' };
    const res = [];

    const dfs = (cur, i) => {
        if(i > digits.length -1) {
            res.push(cur);
            return;
        }
        const letters = map[digits[i]];
        /* 关键 */
        for (const letter of letters) {
            dfs(cur + letter, i + 1);
        }
    }
    dfs('', 0);
    return res;
};

77. 组合 经典

77. 组合

/**
 * @param {number} n
 * @param {number} k
 * @return {number[][]}
 */
var combine = function(n, k) {
    let res = [];
    let path = [];
    const combineHelper = (n, k, startIndex) => {
        if (path.length === k) {
            res.push([...path]);
            return;
        }
        for (let i = startIndex; i <= n; i++) {
            path.push(i);
            combineHelper(n, k, i + 1);
            /* 回溯 */
            path.pop();
        }
    };
    combineHelper(n, k, 1);
    return res;
};

39. 组合总和 经典

39. 组合总和

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum = function(candidates, target) {
    const res = [];
    const dfs = (target, combine, idx) => {
        /* 已经遍历完了,不往下执行 */
        if (idx === candidates.length) {
            return;
        }
        /* 已经找到了合适的,直接push */
        if(target == 0) {
            res.push(combine);
            return;
        }
        dfs(target, combine, idx + 1);
        /* target 执行减法 */
        if (target - candidates[idx] >= 0) {
            dfs(target - candidates[idx], [...combine, candidates[idx]], idx);
        }
    }

    dfs(target, [], 0);
    return res;
};

40. 组合总和 II

40. 组合总和 II

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
    candidates.sort();
    let result = [], combination = [];
    function dfs(nums, target, index, combination, result) {
         if(target === 0) {
             result.push([...combination])
         } else if(target > 0 && index < nums.length) {  // 剪枝
             dfs(nums, target, getNext(nums, index), combination, result);
             combination.push(nums[index]);
             dfs(nums, target - nums[index], index + 1, combination, result);
             combination.pop();
         }
     };
     dfs(candidates, target, 0, combination, result);
     return result;
};

function getNext(nums, index) {
    let next = index;
    while(next < nums.length && nums[next] === nums[index]) {
        next++;
    }
    return next;
}

78. 子集

78. 子集

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var subsets = function(nums) {
    let path = [];
    let res = [];
    const len = nums.length;
    const dfs = (cur, nums) => {
        if (cur === nums.length) {
            res.push([...path]);
            return;
        }
        path.push(nums[cur]);
        dfs(cur + 1, nums);
        path.pop();
        dfs(cur + 1, nums);
    }
    dfs(0, nums);
    return res;
};

131. 分割回文串

131. 分割回文串

/**
 * @param {string} s
 * @return {string[][]}
 */
const isPalindrome = (s, l, r) => {
    for (let i = l, j = r; i < j; i++, j--) {
        if(s[i] !== s[j]) return false;
    }
    return true;
}

var partition = function(s) {
    const res = [], path = [], len = s.length;
    function backtracking(i) {
        if(i >= len) {
            res.push(Array.from(path));
            return;
        }
        for(let j = i; j < len; j++) {
            if(!isPalindrome(s, i, j)) continue;
            path.push(s.substr(i, j - i + 1));
            backtracking(j + 1);
            path.pop();
        }
    }
    backtracking(0);
    return res;
};

47. 全排列 II

47. 全排列 II

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permuteUnique = function(nums) {
    const res = [];
    const vis = new Array(nums.length).fill(false);
    const backtrack = (idx, perm) => {
        if (idx === nums.length) {
            res.push(perm.slice());
            return;
        }
        for (let i = 0; i < nums.length; ++i) {
            if (vis[i] || (i > 0 && nums[i] === nums[i - 1] && !vis[i - 1])) {
                continue;
            }
            perm.push(nums[i]);
            vis[i] = true;
            backtrack(idx + 1, perm);
            vis[i] = false;
            perm.pop();
        }
    }
    nums.sort((x, y) => x - y);
    backtrack(0, []);
    return res;
};

784. 字母大小写全排列

784. 字母大小写全排列

/**
 * @param {string} s
 * @return {string[]}
 */
var letterCasePermutation = function(s) {
    let res = [];
    const dfs = (i, str) => {
        /* 把数字类型的加上 */
        while (!isNaN(s[i])) {
            str += s[i++];
        }
        if (i == s.length) {
            res.push(str);
            return;
        }

        dfs(i+1, str + s[i].toLowerCase());
        dfs(i+1, str + s[i].toUpperCase());
    }
    dfs(0, '');
    return res;
};