贴纸拼词--动态规划

  1. 贴纸拼词

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

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

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

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


public class App
{


    public static void main(String[] args) {
        String[] strs={"with","example","science"};
        System.out.println(new App().minStickers(strs,"thehat"));

      
    }
    public int minStickers(String[] stickers, String target) {
        HashMap<Character,Integer> targetMap=new HashMap<>();
        int n=target.length();
        for(int i=0;i<n;i++){
            char ch=target.charAt(i);
            targetMap.put(ch,targetMap.getOrDefault(ch,0)+1);
        }
        int total=1;
        int[] weight=new int[targetMap.size()];
        char[] chars=new char[targetMap.size()];
        int count=0;
        for(Character ch:targetMap.keySet()){
            chars[count]=ch;
            weight[count]=targetMap.get(ch)+1;
            total*=(weight[count]);
            count++;
        }
        int[][] dp=new int[stickers.length+1][total];
        Arrays.fill(dp[0],-1);
        dp[0][0]=0;
        for(int i=1;i<=stickers.length;i++){
            HashMap<Character,Integer> map=new HashMap<>();
            for(int k=0;k<stickers[i-1].length();k++){
                char ch=stickers[i-1].charAt(k);
                map.put(ch,map.getOrDefault(ch,0)+1);
            }
            for(int j=0;j<total;j++){
                if(j==0) {
                    dp[i][j] = 0;
                    continue;
                }
                dp[i][j]=dp[i-1][j];
                int[] tmpTarget=resolve(j,weight);
                count=0;
                while(updateTarget(tmpTarget,chars,map)!=null){
                    count++;
                    int tmp=dp[i-1][getIndex(tmpTarget,weight)];
                    if(dp[i][j]!=-1) {
                        if (tmp != -1) {
                            dp[i][j] = Math.min(dp[i][j], tmp + count);
                        }
                    }else{
                        if(tmp!=-1){
                            dp[i][j]=tmp+count;
                        }
                    }
                }
            }
        }
        return dp[stickers.length][total-1]==-1?-1:dp[stickers.length][total-1];

    }
    private int[] updateTarget(int[] target,char[] chars,HashMap<Character,Integer> map){
        boolean flag=false;
        for(int i=0;i<chars.length;i++){
            if(target[i]>0&&map.get(chars[i])!=null){
                target[i]-=map.get(chars[i]);
                if(target[i]<0){
                    target[i]=0;
                }
                flag=true;
            }
        }
        if(flag){
            return target;
        }else{
            return null;
        }
    }
    private int[] resolve(int j,int[] weight){
        int[] ans=new int[weight.length];
        for(int i=0;i<weight.length;i++){
            ans[i]=j%weight[i];
            j/=weight[i];
        }
        return ans;
    }
    private int getIndex(int[] tmpTarget,int[] weight){
        int curWeight=1;
        int ans=0;
        for(int i=0;i<tmpTarget.length;i++){
            ans+=curWeight*tmpTarget[i];
            curWeight*=weight[i];
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值