zoukankan      html  css  js  c++  java
  • [leetcode 40. 组合总和 II] 不排序使用哈希表+dfs递归 vs 排序栈+回溯

    题目描述

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

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

    说明:

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

    示例 1:

    输入: candidates = [10,1,2,7,6,1,5], target = 8,
    所求解集为:
    [
      [1, 7],
      [1, 2, 5],
      [2, 6],
      [1, 1, 6]
    ]
    

    示例 2:

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

    方法一 不排序使用哈希表+dfs递归

    • 建立哈希表,统计每个数字出现次数
    • dfs递归剪枝,target减去当前数字,哈希次数减一,进入下一层
    • target==0,找到目标组合,target<0退出
    var combinationSum2 = function(candidates, target) {
        let _hash = {}, ret = [];
        // build hash map
        for (let n of candidates) {
            _hash[n] = typeof _hash[n]=='undefined' ? 1 : _hash[n]+1;
        }
        function dfs(hash, target, solution) {
            if (target == 0) {
                // get it
                ret.push(Object.assign([], solution));
                return true;
            }
            if (target < 0) {
                return false;
            }
            for (let k in hash) {
                if (hash[k] == 0) {continue;}
                solution.push(k);
                hash[k]--;
                dfs(Object.assign({}, hash), target - k, solution);
                // 避免重复,非常关键
                delete hash[k];
                solution.pop();
            }
        }
        dfs(_hash, target, []);
        return ret;
    }
    

    ac之后意外的用时击败了5%的用户,内存击败5%用户,大概这应该算是一种暴力求解,所以速度这么慢?

    方法二 排序栈+回溯

    这是我第一次ac的方法,也是从我39题的基础上直接修改的
    基本思路没有区别,只是在一些边界上稍作变化:

    var combinationSum2 = function(candidates, target) {
        // sort + stack
        candidates.sort();
        let ret = [],stack = [], i = candidates.length-1;
        while (i>=0 || stack.length>0) {
            if (target == 0) {
                // resolved
                let solution = [];
                for (var k in stack) {
                    solution.push(candidates[stack[k]]);
                }
                ret.push(solution);
                let pre = stack.pop();
                target += candidates[pre];
                // 区别1,找到题解,跳过相同数字,避免重复答案
                while (candidates[i] == candidates[pre]){i--;};
                continue;
            } else if (i < 0) {
                pre = stack.pop();
                target+=candidates[pre];
                i = pre - 1;
                // 区别2,索引溢出,本次寻找失败,跳过相同的数字
                while (i>0 && candidates[i] == candidates[pre]) {i--;}
                continue;
            } else if (target >= candidates[i]) {
                // 区别3,入栈之后索引需要移位
                stack.push(i);
                target -= candidates[i];
            }
            i--;
        }
        //
        return ret;
    };
    
  • 相关阅读:
    [LeetCode] Output Contest Matches 输出比赛匹配对
    [LeetCode] 527. Word Abbreviation 单词缩写
    [LeetCode] Permutation in String 字符串中的全排列
    [LeetCode] 560. Subarray Sum Equals K 子数组和为K
    [LeetCode] Reshape the Matrix 重塑矩阵
    [LeetCode] 536. Construct Binary Tree from String 从字符串创建二叉树
    [LeetCode] IPO 上市
    [LeetCode] Binary Tree Tilt 二叉树的坡度
    [LeetCode] Array Partition I 数组分割之一
    [LeetCode] Zuma Game 祖玛游戏
  • 原文地址:https://www.cnblogs.com/dapianzi/p/12704549.html
Copyright © 2011-2022 走看看