466. Count The Repetitions

Define S = [s,n] as the string S which consists of n connected strings s. For example, ["abc", 3] ="abcabcabc".

On the other hand, we define that string s1 can be obtained from string s2 if we can remove some characters from s2 such that it becomes s1. For example, “abc” can be obtained from “abdbec” based on our definition, but it can not be obtained from “acbbe”.

You are given two non-empty strings s1 and s2 (each at most 100 characters long) and two integers 0 ≤ n1 ≤ 106 and 1 ≤ n2 ≤ 106. Now consider the strings S1 and S2, where S1=[s1,n1] and S2=[s2,n2]. Find the maximum integer M such that [S2,M] can be obtained from S1.

Example:

Input:
s1="acb", n1=4
s2="ab", n2=2

Return:
2


思路:最开始想:找个n,m使得找到n个s1恰好组合出m个s2的情况,先求整体再把零散的求出来

package l466;

import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;

/**
 * 找到n个s1恰好组合出m个s2的情况
 * 
 * 果然这样会出现一些问题,其实保险的办法就是完全地brute force模拟
 * 其实遇到这种情况在面试场上肯定没那么多的事件来考虑,直接写brute force反而还更快点
 */
public class WA {
    public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
    	if(s1.length()*n1 < s2.length()*n2)	return 0;
        Set<String> s = new HashSet<String>();
        int n = 1, m = 0;
        char[] cs1 = s1.toCharArray(), cs2 = s2.toCharArray();
        int np = 0, mp = 0;
        TreeMap<Integer, Integer> count = new TreeMap<Integer, Integer>();
        count.put(0, 0);
        int preEnd = 0;
        boolean f = true;
        
        while(f) {
        	
        	while(cs1[np] != cs2[mp]) {
        		np ++;
        		if(np == cs1.length) {
        			String left = new String(cs1, preEnd, cs1.length-preEnd);
            		if(s.contains(left)) {
            			f = false;
            			break;
            		}
            		s.add(left);
            		
        			count.put(n, mp);
        			np = 0;
        			n ++;
        		}
        	}
        	
        	np++;
        	if(np == cs1.length) {
        		String left = new String(cs1, preEnd, cs1.length-preEnd);
        		if(s.contains(left)) {
        			f = false;
        			break;
        		}
        		s.add(left);
        		
    			count.put(n, mp);
    			np = 0;
    			n ++;
    		}
        	
        	mp++;
        	if(mp == cs2.length) {
        		preEnd = np;
        		m++;
        		mp = 0;
        	}
        	
        }
        
        int maxS2 = n1/n*m;
        int remainingS1 = n1-n1/n*n;
        maxS2 += count.get(count.floorKey(remainingS1));
        int ret = maxS2 / n2;
        
        return ret;
    }
}

WA自后,想直接用brute force,反正思路都是差不多的,所以说,可能你实现一些代码可能最后并不能解决问题,但是却在这个过程中的一些思想确实相同的

package l466;


public class TLE {
    public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
    	if(s1.length()*n1 < s2.length()*n2)	return 0;
        int n = 1, m = 0;
        char[] cs1 = s1.toCharArray(), cs2 = s2.toCharArray();
        int np = 0, mp = 0;
        
        while(n <= n1) {
        	
        	while(n <= n1 && cs1[np] != cs2[mp]) {
        		np ++;
        		if(np == cs1.length) {
        			np = 0;
        			n ++;
        		}
        	}
        	
        	mp++;
        	if(mp == cs2.length) {
        		m++;
        		mp = 0;
        	}
        	
        	np++;
        	if(np == cs1.length) {
        		np = 0;
    			n ++;
    		}
        }
        
        return m/n2;
        
    }
}

写完却TLE,换种方式AC,应该是快接近时间极限了吧,程序结构上的调整也会带来一点优化

/*
 * 这种接近TLE的时候可能都需要调整while循环了
 */
public class Solution {
    public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
    	if(s1.length()*n1 < s2.length()*n2)	return 0;
        int n = 1, m = 0;
        char[] cs1 = s1.toCharArray(), cs2 = s2.toCharArray();
        int np = 0, mp = 0;
        
        while(n <= n1) {
        	
        	if(cs1[np] == cs2[mp]) {
        		mp ++;
        		if(mp == cs2.length) {
            		m++;
            		mp = 0;
            	}
        	}

        	np++;
        	if(np == cs1.length) {
        		np = 0;
    			n ++;
    		}
        }
        
        return m/n2;
        
    }
}


最后付一个Discuss里面的解法

Given a str2, for each str, we can give a value v to this str such that, after greedily looking through str, our imaginary next step is to find str2[v].
In our problem, str is always (str1,n), with a given str1, so, we can take one more step and say that for each n, there is a unique v associated to n(i.e t0 (str,n)).

define a division and a modulo between two strings as follow:

str/str2=argmax{i, (str2,i) can be obtained by str}
str%str2=the v mentioned above associated with str.

All possible values of v is less than str2.size(),
so (str1,n)%str2 will begin to repeat a pattern after a certain n less than str2.size().
(the pattern is the same because in the cases with the same v, our situations are exactly the same),
so is (str1,n)/str2-(str1,n+1)/str2 for the same reason.
We can therefore precompute a table for all these values with O(str1.length*str2.length).

(str1,n) can be divided in three parts:

sth before pattern(A) + pattern parts(B) + sth after pattern(C)

The pattern does not necessarily begin in the first str1, we shall see if n is great enough so that there can be a pattern.

The last pattern(C) is not necessarily complete, we need to calculate it separately.

We can finish in just looking to the precomputed table and doing some simple maths.

class Solution {
public:
    int getMaxRepetitions(string s1, int n1, string s2, int n2) {
        vector<int> rapport(102,-1);
        vector<int> rest(102,-1);
        int b=-1;int posRest=0;int rap=0;
        int last=-1;
        rapport[0]=rest[0]=0;//case when n=0
        for(int i=1;i<=s2.size()+1;i++){
            int j;
            for(j=0;j<s1.size();j++){
                if(s2[posRest]==s1[j]){
                    posRest++;
                    if(posRest==s2.size()){
                        rap++;
                        posRest=0;
                    }
                }
            }
            for(int k=0;k<i;k++){
                if(posRest==rest[k]){b=k;last=i;break;}
            }
            rapport[i]=rap;rest[i]=posRest;
            if(b>=0)break;
        }
        int interval=last-b;
        if(b>=n1)return rapport[n1]/n2;
        return ((n1-b)/interval*(rapport[last]-rapport[b])+rapport[(n1-b)%interval+b])/n2;
//corrected thanks to @zhiqing_xiao and @iaming 
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值