动态规划——StickersToSpellWord

简介: 动态规划——StickersToSpellWord

题目

**给定一个字符串str,给定一一个字符串类型的数组arr。
arr里的每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来。
返回需要至少多少张贴纸可以完成这个任务。
例子: str= “babac”,arr = {“ba”,“c”,“abcd”}
至少需要两张贴纸"ba"和"abcd",因为使用这两张贴纸,把每一个字符单独剪开,含有2个a、2个b、1个c。是可以拼出str的。所以返回2。
提示:可变参数能少则少,可变参数越少,缓存结构的命中率越高**

package com.harrison.class13;

import java.util.HashMap;

public class Code07_StickersToSpellWord {
    // 伪代码
//    public static int getMinStickers(String rest,String[] arr) {
//        // 加过滤 保证所有贴纸里的字符能够覆盖目标字符串
//    }
//    
//    public static int minStickers(String rest,String[] arr) {
//        if(rest.equals("")) {
//            return 0;
//        }
//        int next=0;
//        for(String first:arr) {
//            rest-first -> nextRest;
//            int cur=minStickers(nextRest, arr);
//            next=Math.min(next, cur);
//        }
//        return next+1;
//    }
    
    public static int minStickers1(String[] stickers,String target) {
        int n=stickers.length;
        int[][] map=new int[n][26];
        for(int i=0; i<n; i++) {
            char[] str=stickers[i].toCharArray();
            for(char c:str) {
                map[i][c-'a']++;
            }
        }
        HashMap<String, Integer> dp=new HashMap<>();
        dp.put("", 0);
        return process1(dp, map, target);
    }
    
    // dp 傻缓存,如果rest已经算过了,直接返回dp中的值
    // 0...N中每一个字符串所含字符的词频统计
    // 返回值是-1,map中的贴纸无论如何都无法搞定rest
    public static int process1(HashMap<String, Integer> dp,int[][] map,String rest) {
        if(dp.containsKey(rest)) {
            return dp.get(rest);
        }
        // 搞定rest,使用最少的贴纸数量
        int ans=Integer.MAX_VALUE;
        // n种贴纸
        int n=map.length;
        // tmap替代rest
        int[] tmap=new int[26];
        char[] target=rest.toCharArray();
        for(char c:target) {
            tmap[c-'a']++;
        }
        // map-tmap
        for(int i=0; i<n; i++) {// 枚举当前第一张贴纸是谁
            // 小贪心 确保贴纸中至少含有目标字符串中的一种字符才进行尝试
            // 目标字符串中0位置的字符,当前贴纸是否有
            if(map[i][target[0]-'a']==0) {
                continue;
            }
            StringBuilder sb=new StringBuilder();
            // i 当前来到的第一张贴纸
            // j 枚举a~z字符
            for(int j=0; j<26; j++) {
                if(tmap[j]>0) {// j这个字符是target需要的(要搞定的字符串里有这个字符)
                    for(int k=0; k<Math.max(0, tmap[j]-map[i][j]); k++) {
                        sb.append((char)('a'+j));
                    }
                }
            }
            // 经历上面的for循环后,目标字符串减去了第一张贴纸(i)里的字符,
            // 剩余的字符在sb里面
            String s=sb.toString();
            int tmp=process1(dp, map, s);
            if(tmp!=-1) {
                ans=Math.min(ans, tmp+1);
            }
        }
        dp.put(rest, ans==Integer.MAX_VALUE?-1:ans);
        return dp.get(rest);
    }
    
    public static void main(String[] args) {
        String[] arr= {"aaaa","bbaa","ccddd"};
        String str="abcccccdddddbbbaaaaa";
        System.out.println(minStickers1(arr,str));
    }
}
相关文章
|
6月前
|
算法 测试技术 C++
|
6月前
|
C++ NoSQL 容器
动态规划二
动态规划二
|
算法
【学会动态规划】按摩师(11)
【学会动态规划】按摩师(11)
53 0
|
6月前
|
机器人 NoSQL 容器
动态规划一
动态规划一
|
6月前
|
存储 JavaScript 机器人
动态规划问题
动态规划问题
42 0
|
6月前
动态规划1
动态规划1
38 0
动态规划1
|
存储
【动态规划】
【动态规划】
|
6月前
动态规划
动态规划
53 0
|
人工智能
动态规划的证明题
动态规划的证明题
110 0
|
算法 前端开发 JavaScript
理解动态规划
理解动态规划
理解动态规划