Substring with Concatenation of All Words

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

For example, given:
s"barfoothefoobarman"
words["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

思路:暴力解法:就是 i 扫描到 s.length() - words[0].length * words.length; 然后用hashmap进行统计一次,然后每次走的时候,就进行更新,满足条件就加到list中。这题其实最规范的应该是当hashmap清空的时候就加list。

public class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> list = new ArrayList<Integer>();
        int wordlen = words[0].length();
        int totallen = wordlen*words.length;
        if(s == null || s.length() < totallen) return list;
        
        HashMap<String,Integer> hashmap = new HashMap<String, Integer>();
        for(String str: words) {
            if(hashmap.containsKey(str)) {
                hashmap.put(str, hashmap.get(str)+1);
            } else {
                hashmap.put(str,1);
            }
        }
        
        for(int i=0; i<=(s.length() - totallen); i++){
            HashMap<String, Integer> newmap = new HashMap<String,Integer>(hashmap);
            int start = i;
            while(start<=s.length()-wordlen){
                String str = s.substring(start, start+wordlen);
                if(newmap.containsKey(str) && newmap.get(str)>0){
                    start +=wordlen;
                    if(newmap.get(str) == 1){
                        newmap.remove(str);
                    } else {
                         newmap.put(str, newmap.get(str)-1);
                    }
                   
                } else {
                    break;
                }
                if(newmap.size() ==0){
                    list.add(i);
                }
            }
        }
        return list;
    }
}

更好的窗口法:就是起点是word length以内为起点,然后j每次移动wordlen的距离,这样可以包含所有的wordlen的情况,那么j往后移动,start相应的来滑动,并更新当前的curDict和count,相当于滑动word len个 i,j窗口,所以最后复杂度是O(wordlen*n) = O(n)的。懂得了滑动窗口,这题应该不难,只是每次移动wordlen个位置,而且要需要移动wordlen次窗口运算,想到这点,比较难。另外,start怎么移动,这个也是个考点。start移动法则就是:如果当count word 大于了应有的次数,那么start往右边移动。并且update字典频率和count。

public class Solution {
    public List<Integer> findSubstring(String s, String[] words) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(s == null || words == null || s.length() == 0 || words.length == 0) return list;
        HashMap<String, Integer> hashmap = new HashMap<String, Integer>();
        for(int i=0; i<words.length; i++) {
            String str = words[i];
            Integer k = hashmap.get(str);
            if(k == null) {
                hashmap.put(str, 1);
            } else {
                hashmap.put(str, k+1);
            }
        }
        
        int wordlen = words[0].length();
        for(int i=0; i<wordlen; i++){
            int start = i;
            HashMap<String, Integer> curDict = new HashMap<String, Integer>();
            int len = 0;
            for(int j=i; j<=s.length()-wordlen; j+=wordlen){
                String str = s.substring(j, j+wordlen);
                if(!hashmap.containsKey(str)){
                    len = 0;
                    curDict.clear();
                    start = j+wordlen;
                } else { // hashmap.containsKey(str);
                    if(curDict.containsKey(str)){
                        curDict.put(str, curDict.get(str)+1);
                    } else {
                        curDict.put(str, 1);
                    }
                    
                    if(curDict.get(str)<= hashmap.get(str)){
                        len++;
                    } else { // curDict.get(str) > hashmap.get(str);
                        while(curDict.get(str) > hashmap.get(str)){ // 因为前面已经加进去了,现在要移动start指针,来update;
                            String temp = s.substring(start, start+wordlen);
                            if(curDict.containsKey(temp)){
                                curDict.put(temp, curDict.get(temp)-1);
                            }
                            if(curDict.get(temp) < hashmap.get(temp)){
                                len--;
                            }
                            start += wordlen;
                        }
                    }
                    if(len == words.length){
                        list.add(start);
                        String temp = s.substring(start, start+wordlen);
                        if(curDict.containsKey(temp)){
                            curDict.put(temp, curDict.get(temp)-1);
                        }
                        if(curDict.get(temp) < hashmap.get(temp)){
                            len--;
                        }
                        start += wordlen;
                    }
                }
            }
        }
        return list;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值