【我也想刷穿 LeetCode啊】691. 贴纸拼词

109 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情

现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。

因此每天刷刷LeetCode非常有必要

在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode

一、题目描述

我们有 n 种不同的贴纸。每个贴纸上都有一个小写的英文单词。

您想要拼写出给定的字符串 target ,方法是从收集的贴纸中切割单个字母并重新排列它们。如果你愿意,你可以多次使用每个贴纸,每个贴纸的数量是无限的。

返回你需要拼出 target 的最小贴纸数量。如果任务不可能,则返回 -1 。

注意:在所有的测试用例中,所有的单词都是从 1000 个最常见的美国英语单词中随机选择的,并且 target 被选择为两个随机单词的连接。

 

示例 1:

输入: stickers = ["with","example","science"], target = "thehat" 输出:3 解释: 我们可以使用 2 个 "with" 贴纸,和 1 个 "example" 贴纸。 把贴纸上的字母剪下来并重新排列后,就可以形成目标 “thehat“ 了。 此外,这是形成目标字符串所需的最小贴纸数量。

二、思路分析

  1. 把stickers中的每一项(字符串)放入一个长度为26的数组里,数组的下标代表当前字符的charCode相对'a'的charCode的偏移量
  2. 把target(字符串)放入一个长度为26的数组里,数组的下标代表当前字符的charCode相对'a'的charCode的偏移量
  3. stickers中以每一项作为第一个,所有分支挨个试一遍
  4. 剪枝优化,当前的sticker包含target中的第一个字符

三、代码实现

/**
 * @param {string[]} stickers
 * @param {string} target
 * @return {number}
 */
const ACharCode = 97;
var minStickers = function(stickers, target) {
  const N = stickers.length;
  let counts = Array(N).fill().map(() => Array(26).fill(0));
  let charCodeIndex;
  // 把stickers中的每一项(字符串)放入一个长度为26的数组里,数组的下标代表当前字符的charCode相对'a'的charCode的偏移量
  for(let i = 0; i < N; i++) {
    for (let j = 0; j < stickers[i].length; j++) {
      charCodeIndex = stickers[i][j].charCodeAt(0) - ACharCode;
      counts[i][charCodeIndex]++;
    }
  }

  let dp = new Map();
  dp.set("", 0);
  let ans = process(counts, target, dp);

  return ans === Number.MAX_SAFE_INTEGER ? -1 : ans;
};

function process(stickers, t, dp) {
  if (dp.has(t)) {
    return dp.get(t);
  }

  // 把target(字符串)放入一个长度为26的数组里,数组的下标代表当前字符的charCode相对'a'的charCode的偏移量
  let tcounts = Array(26).fill(0);
  for (let i = 0; i < t.length; i++) {
    tcounts[t[i].charCodeAt(0) - ACharCode]++;
  }

  const N = stickers.length;
  let min = Number.MAX_SAFE_INTEGER;
  // stickers中以每一项作为第一个,所有分支挨个试一遍
  for (let i = 0; i < N; i++) {
    let sticker = stickers[i];
    // 剪枝优化,当前的sticker包含target中的第一个字符
    if (sticker[t.charCodeAt(0) - ACharCode] > 0) {
      let builder = [];
      for (let j = 0; j < 26; j++) {
        if (tcounts[j] > 0) {
          let nums = tcounts[j] - sticker[j];
          for (let k = 0; k < nums; k++) {
            builder.push(j + ACharCode);
          }
        }
      }
      const rest = String.fromCharCode(...builder);
      min = Math.min(min, process(stickers, rest, dp));
    }
  }

  let ans = min + ((min === Number.MAX_SAFE_INTEGER) ? 0 : 1);
  dp.set(t, ans);

  return ans;

}

四、总结

以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~