Java實現 LeetCode 691 貼紙拼詞(DFS+map記錄)

691. 貼紙拼詞

咱們給出了 N 種不一樣類型的貼紙。每一個貼紙上都有一個小寫的英文單詞。java

你但願從本身的貼紙集合中裁剪單個字母並從新排列它們,從而拼寫出給定的目標字符串 target。app

若是你願意的話,你能夠不止一次地使用每一張貼紙,並且每一張貼紙的數量都是無限的。ide

拼出目標 target 所需的最小貼紙數量是多少?若是任務不可能,則返回 -1。測試

示例 1:ui

輸入:spa

[「with」, 「example」, 「science」], 「thehat」
輸出:code

3
解釋:ci

咱們能夠使用 2 個 「with」 貼紙,和 1 個 「example」 貼紙。
把貼紙上的字母剪下來並從新排列後,就能夠造成目標 「thehat「 了。
此外,這是造成目標字符串所需的最小貼紙數量。
示例 2:字符串

輸入:get

[「notice」, 「possible」], 「basicbasic」
輸出:

-1
解釋:

咱們不能經過剪切給定貼紙的字母來造成目標「basicbasic」。

提示:

stickers 長度範圍是 [1, 50]。
stickers 由小寫英文單詞組成(不帶撇號)。
target 的長度在 [1, 15] 範圍內,由小寫字母組成。
在全部的測試案例中,全部的單詞都是從 1000 個最多見的美國英語單詞中隨機選取的,目標是兩個隨機單詞的串聯。
時間限制可能比平時更具挑戰性。預計 50 個貼紙的測試案例平都可在35ms內解決。

class Solution {
   public int minStickers(String[] stickers, String target) {
        int m = stickers.length;
        int[][] mp = new int[m][26];
        Map<String, Integer> dp = new HashMap<>();
        for (int i = 0; i < m; i++)
            for (char c : stickers[i].toCharArray()) mp[i][c - 'a']++;
        dp.put("", 0);
        return helper(dp, mp, target);
    }

    private int helper(Map<String, Integer> dp, int[][] mp, String target) {
        if (dp.containsKey(target)) return dp.get(target);
        int ans = Integer.MAX_VALUE, n = mp.length;
        int[] tar = new int[26];
        for (char c : target.toCharArray()) tar[c - 'a']++;
        for (int i = 0; i < n; i++) {
            if (mp[i][target.charAt(0) - 'a'] == 0) continue;
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 26; j++) {
                if (tar[j] > 0)
                    for (int k = 0; k < Math.max(0, tar[j] - mp[i][j]); k++)
                        sb.append((char) ('a' + j));
            }
            String s = sb.toString();
            int tmp = helper(dp, mp, s);
            if (tmp != -1) ans = Math.min(ans, 1 + tmp);
        }
        dp.put(target, ans == Integer.MAX_VALUE ? -1 : ans);
        return dp.get(target);
    }
}
相關文章
相關標籤/搜索