算法—动态规划(5)

126 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

问题是从一个备选词库找到一系列字母组合,将这些字母组合按一定顺序组合成目标单词。还是通过图来解释问题。

can_construct_001.png

目标单词 adcdef 数组为 [ad,abc,cd,def,abcd],这里我们需要从前向后一个个截取单词,不可以从中间来截取单词。所以这里如果用 cd 去截取字符串剩余字母顺序就被打乱了。

can_construct_002.png

我们可以看每条分支也就是一条一条路径来看,首先是最左侧的路径为 [ab,cd] 剩余的 ef[ad,abc,cd,def,abcd] 中找不到对应字母组合所以这两条路径在叶子节点返回的是 ef 返回 false 当两个叶子节点返回不同值相遇falsetrue 只要有一个 true 就返回为 true。在看第二条路径,[abc,def] 满足条件,剩余为 ''

can_construct_003.png

can_construct_005.png

上面例子中,每一个分支都是返回 false,也就是在给出数组将这些元素任意组合都无法得到目标单词。

const canConstructor = (target,wordBank)=>{
    if(target === ''){
        return true;
    }

    for(let word of wordBank){
        if(target.indexOf(word) === 0 ){
            const suffix = target.slice(word.length);
            if(canConstructor(suffix,wordBank) === true){
                return true;
            }
        }
    }

    return false;
}

target.indexOf(word) === 0 判断是目标单词前几个字母是否存在对应的字母组合存 wordBankconst suffix = target.slice(word.length) 将找到的字母组合前缀截取掉,剩下字符串作为输入到函数canConstructor

优化

优化算法还是通过缓存方式将结果缓存起来,在下一次调用时候直接读取缓存避免重复计算。

const canConstructorWithMemo = (target,wordBank,memo={})=>{

    if(target in memo) return memo[target]

    if(target === ''){
        return true;
    }

    for(let word of wordBank){
        if(target.indexOf(word) === 0 ){
            const suffix = target.slice(word.length);
            if(canConstructorWithMemo(suffix,wordBank,memo) === true){
                memo[target] = true
                return memo[target];
            }
        }
    }
    memo[target] = false;
    return memo[target];
}

const res = canConstructor('abcdef',['ab','abc','cd','def','abcd'])
console.log(res);

const res1 = canConstructor('skateboard',['bo','rd','ate','t','ska','sk','boar'])
console.log(res1);

const res2 = canConstructorWithMemo('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeef',[
    'e',
    'ee',
    'eee',
    'eeee',
    'eeeee',
    'eeeeee',
    'eeeeeee',
    'eeeeeeee',
    'eeeeeeeeee',
])

console.log(res2)