JAVA程序设计:戳印序列(LeetCode:936)

你想要用小写字母组成一个目标字符串 target。 

开始的时候,序列由 target.length 个 '?' 记号组成。而你有一个小写字母印章 stamp。

在每个回合,你可以将印章放在序列上,并将序列中的每个字母替换为印章上的相应字母。你最多可以进行 10 * target.length  个回合。

举个例子,如果初始序列为 "?????",而你的印章 stamp 是 "abc",那么在第一回合,你可以得到 "abc??"、"?abc?"、"??abc"。(请注意,印章必须完全包含在序列的边界内才能盖下去。)

如果可以印出序列,那么返回一个数组,该数组由每个回合中被印下的最左边字母的索引组成。如果不能印出序列,就返回一个空数组。

例如,如果序列是 "ababc",印章是 "abc",那么我们就可以返回与操作 "?????" -> "abc??" -> "ababc" 相对应的答案 [0, 2];

另外,如果可以印出序列,那么需要保证可以在 10 * target.length 个回合内完成。任何超过此数字的答案将不被接受。

 

示例 1:

输入:stamp = "abc", target = "ababc"
输出:[0,2]
([1,0,2] 以及其他一些可能的结果也将作为答案被接受)
示例 2:

输入:stamp = "abca", target = "aabcaca"
输出:[3,0,1]
 

提示:

1 <= stamp.length <= target.length <= 1000
stamp 和 target 只包含小写字母。

思路:我们可以倒着思考问题,假如说最终是可以印出来目标数组的,则最后一个印章的位置是不会被覆盖的,我们考虑当前最后一次印章的位置,从它开始和stamp数组进行比较,如果相等,则将他们替换成‘?’,然后将数组按照该位置分成两部分,再查找这两部分分别最后一次印章的位置,并比较(要注意这里的比较中是含有‘?’,而‘?’是可以和任意字符匹配的哦),由于问题已经分解为两个子问题了,剩下的就是采取和第一次相同的步骤而已。

class Solution {
	
	private boolean flag;
	
    public int[] movesToStamp(String stamp, String target) {

    	flag=false;
    	List<Integer> list=new ArrayList<>();
    	
    	list=work(0,stamp,target);
    	
    	if(flag) return new int[0];
    	
    	int[] arr=new int[list.size()];
    	
    	for(int i=0;i<list.size();i++)
    		arr[i]=list.get(i);
    	
    	return arr;
    }
    
    private List<Integer> work(int index,String a,String b){
    	
    	if(b.length()<a.length() || !jud(b) || flag) 
    		return new ArrayList<>();
    	
    	boolean mark=false;
    	List<Integer> res=new ArrayList<>();
    	
    	for(int i=0;i<b.length();i++) {
    		if(i+a.length()>b.length())
    			break;
    		if(!jud(b.substring(i, i+a.length())))
    			continue;
    		if(check(b.substring(i, i+a.length()),a)) {
    			mark=true;
    			StringBuilder tmp=new StringBuilder(b.substring(0, i));
    			for(int j=0;j<a.length();j++)
    				tmp.append('?');
    			tmp.append(b.substring(i+a.length()));
    			res.addAll(work(index,a,tmp.toString().substring(0, i+a.length()-1)));
    			res.addAll(work(index+i+1,a,tmp.toString().substring(i+1)));
    			res.add(index+i);
    			break;
    		}
    	}
    	
    	if(!mark) flag=true;
    	
    	return res;
    }
    
    private boolean jud(String a) {
    	
    	for(int i=0;i<a.length();i++) {
    		if(a.charAt(i)!='?')
    			return true;
    	}
    	
    	return false;
    	
    }
    
    private boolean check(String a,String b) {
    	for(int i=0;i<a.length();i++) {
    		if(a.charAt(i)!=b.charAt(i) && a.charAt(i)!='?')
    			return false;
    	}
    	return true;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值