LeetCode030 Substring with Concatenation of All Words

本文提供了LeetCode第30题“包含所有单词的子串”多种编程语言的解决方案,包括Java、C和Python,并针对每种语言提供了解题思路及代码实现。

详细见:leetcode.com/problems/substring-with-concatenation-of-all-words


Java Solution: github

package leetcode;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

public class P030_SubstringWithConcatenationOfAllWords {
	public static void main(String[] args) {
		System.out.println(new Solution2().findSubstring("wordgoodgoodgoodbestword", new String[]{"word","good","best","good"}));;
		System.out.println(new Solution2().findSubstring("barfoothefoobarman", new String[]{"foo", "bar"}));;
		System.out.println(new Solution2().findSubstring("bbbbbb", new String[]{"b", "b", "b", "b"}));;
	}
	/*
	 * 	土方法,KMP
	 * 	算法正确性没有错
	 * 	TLE
	 * 	74 ms
	 * 	44.40%
	 * 	141 ms
	 * 	40.37%
	 */
	static class Solution1 {
		public List<Integer> findSubstring(String s, String[] words) {
			List<Integer> ans = new LinkedList<Integer>();
			int wordlen = 0;
			if (s == null || s.length() == 0 || words == null || words.length == 0 || (wordlen = words[0].length()) == 0)
				return ans;
			char[] sc = s.toCharArray(), wc = null;
			int[] sign = new int[sc.length], next = null, judge = new int[words.length];
			Arrays.fill(sign, -1);	Arrays.fill(judge, 0);
			HashMap<String, Integer> judgeMap = new HashMap<String, Integer>();
			for (int i = words.length - 1; i != -1; i --) {
				if (judgeMap.containsKey(words[i])) {
					judge[judgeMap.get(words[i])] ++;
				} else {
					judgeMap.put(words[i], i);
					judge[i] ++;
				}
			}
//			if (judgeMap.size() == 1 && words[0].equals("a")) {
//				for (int i = 0; i < s.length() - words.length + 1; i ++)
//					ans.add(i);
//				return ans;
//			}
			for (int i = 0; i != words.length; i ++) {
				if (judgeMap.get(words[i]) != i)
					continue;
				wc = words[i].toCharArray();
				next = getNext(wc);
				int si = 0, pi = 0;
				while (si != sc.length) {
					if (-1 == pi || sc[si] == wc[pi]) {
						si ++;   pi ++;
					} else 
						pi = next[pi];
					if (pi == wc.length) {
						sign[si - wc.length] = i;
						si -= wc.length - 1;
						pi = 0;
					}
				}
			}
			int[] map = new int[words.length];
			boolean[] isAdd = new  boolean[sign.length];
			Arrays.fill(isAdd, false);
			for (int i = 0; i != sign.length; i ++) {
				if (sign[i] == -1)
					continue;
				int new_i = 0;
				if ((new_i = i - wordlen) > -1) {
					int sign_index = words.length * wordlen + new_i;
					if (sign_index < sign.length && sign[new_i] == sign[sign_index]) {
						isAdd[i] = isAdd[new_i];
						if (isAdd[new_i]) {
							ans.add(i);
						}
						continue;
					}
				}
				Arrays.fill(map, 0);
				map[sign[i]] ++;
				for (int j = 1; j != words.length; j ++) {
					int temp = j * wordlen + i;
					if (temp >= sign.length || sign[temp] == -1)
						break;
					map[sign[temp]] ++;
				}
				boolean isTrue = map[0] == judge[0];
				for(int j = 1; j != map.length; j ++)
					isTrue &= map[j] == judge[j];
				if (isTrue) {
					ans.add(i);
					isAdd[i] = true;
				}
			}
			return ans;
	    }
		int[] getNext(char[] c) {
			int[] next = new int[c.length];
			next[0] = -1;
			int cur = 0, pre = -1;
			while (cur != c.length - 1) {
				if (pre == -1 || c[pre] == c[cur]) {
					pre ++;   cur ++;
					next[cur] = pre;
				} else 
					pre = next[pre];
			}
			return next;
		}
	}
	//AC 30ms 87.95%
	static class Solution2 {
	    public List<Integer> findSubstring(String s, String[] words) {
	        int len1 = s == null ? 0 : s.length(), len2 = words == null ? 0 : words.length;
	        LinkedList<Integer> answer = new LinkedList<Integer>();
	        if (len1 == 0 || len2 == 0) return answer;
	        HashMap<String, Integer> map1 = new HashMap<String, Integer>();    //保存s上
	        HashMap<String, Integer> map2 = new HashMap<String, Integer>();    //保存words上
	        for (String word : words) map2.put(word, map2.getOrDefault(word, 0) + 1);
	        int wl = words[0].length(), left = 0, count = 0;
	        for (int i = 0; i < wl; i ++) {
	            map1.clear();
	            left = i;
	            count = 0;
	            for (int j = i; j <= len1 - wl; j += wl) {
	                String s1 = s.substring(j, j + wl);
	                if (map2.containsKey(s1)) {
	                    map1.put(s1, map1.getOrDefault(s1, 0) + 1);
	                    count ++;
                        while (map1.get(s1) > map2.get(s1)) {
                            String s2 = s.substring(left, left + wl);
                            map1.put(s2, map1.get(s2) - 1);
                            left += wl;
                            count --;
                        }
	                    if (count == len2) {
	                        answer.add(left);
                            String s2 = s.substring(left, left + wl);
                            map1.put(s2, map1.get(s2) - 1);
	                        left += wl;
	                        count --;
	                    }
	                } else {
	                    map1.clear();
	                    count = 0;
	                    left = j + wl;
	                }
	            }
	        }
	        return answer;
	    }
	}
}


C Solution: github

/*
    url: leetcode.com/problems/substring-with-concatenation-of-all-words/
    46ms 100.0%
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
    
int cmp(char * s1, int i1, char * s2, int i2, int len) {
    int i = 0;
    for (i = 0; i < len; i ++) {
        if (*(s1 + i1 + i) != *(s2 + i2 + i))
            return 0;
    }
    return 1;
}

int contains(char * s1, char ** record_char, int record_size, int len) {
    int i = 0;
    for (i = 0; i < record_size; i ++) {
        if (cmp(s1, 0, *(record_char + i), 0, len))
            return i;
    }
    return -1;
}

int* findSubstring(char* s, char** words, int len2, int* returnSize) {
    int len1 = s == NULL ? 0 : strlen(s);
    int wl = 0, left = 0, count = 0, record_size = 1, wi = 0, sign = 1;
    int * arr1 = NULL, * arr2 = NULL, i = 0, j = 0, k = 0, v = 0, vv = 0;
    char ** record_char = NULL;
    int * record_int = NULL, * target_int = NULL;
    int * answer = (int *) malloc(sizeof(int) * len1), answer_capacity = len1;
    int answer_index = 0, * answer_temp = NULL;

    if (len1 == 0 || len2 == 0) return NULL;
    wl = strlen(*(words + 0));
    for (i = 1; i < len2; i ++) {
        for (j = 0, sign = 0; ! sign & (j < i); j ++)
            sign |= cmp(*(words + j), 0, *(words + i), 0, wl);
        if (! sign) record_size ++;
    }
    record_char = (char **)(malloc(sizeof(char *) * record_size));
    record_int = (int *)(malloc(sizeof(int) * record_size));
    target_int = (int *)(malloc(sizeof(int) * record_size));
    for (i = 0; i < record_size; i ++) *(target_int + i) = 0;
    for (i = 0; i < record_size; i ++) *(record_int + i) = 0;
    *(record_char + 0) = *(words + 0);
    *(target_int + 0) += 1;
    for (i = 1, wi = 1; i < len2; i ++) {
        for (j = 0, sign = 0; ! sign & (j < i); j ++)
            sign |= cmp(*(words + j), 0, *(words + i), 0, wl);
        if (! sign) {
            *(record_char + (wi ++)) = *(words + i);
            *(target_int + j) += 1;
        } else {
            *(target_int + j - 1) += 1;
        }
    }
    for (i = 0; i < wl; i ++) {
        left = i;
        count = 0;
        for (k = 0; k < record_size; k ++)
            *(record_int + k) = 0;
        for (j = i; j <= len1 - wl; j += wl) {
            v = contains(s + j, record_char, record_size, wl);
            if (v != -1) {
                *(record_int + v) += 1;
                count ++;
                while (*(target_int + v) < *(record_int + v)) {
                    vv = contains(s + left, record_char, record_size, wl);
                    *(record_int + vv) -= 1;
                    count --;
                    left += wl;
                }
                if (count == len2) {
                    //ensure answer size
                    if (answer_index == answer_capacity) {
                        answer_temp = (int *)malloc(sizeof(int) * answer_capacity * 2);
                        for (vv = 0; vv < answer_capacity; vv ++)
                            answer_temp[vv] = answer[vv];
                        free(answer);
                        answer = answer_temp;
                        answer_capacity = answer_capacity * 2;
                    }
                    answer[answer_index ++] = left;
                    vv = contains(s + left, record_char, record_size, wl);
                    *(record_int + vv) -= 1;
                    count --;
                    left += wl;
                }
            } else {
                left = j + wl;
                count = 0;
                for (k = 0; k < record_size; k ++)
                    *(record_int + k) = 0;
            }
        }
    }
    * (returnSize + 0) = answer_index;
    free(record_char);
    free(record_int);
    return answer;
}

int main() {
    char * s = "bbbbbb";
    char ** words = NULL;
    char * w0 = "b";
    char * w1 = "b";
    char * w2 = "b";
    char * w3 = "b";
    int len2 = 4;
    int returnSize = 0;
    int * answer = NULL;
    int i = 0;
    words = (char **)(malloc(sizeof(char *) * len2));
    *(words + 0) = w0;
    *(words + 1) = w1;
    *(words + 2) = w2;
    *(words + 3) = w3;
    answer = findSubstring(s, words, len2, &returnSize);
    for (i = 0; i < returnSize; i ++)
        printf("%d ", *(answer + i));
    printf("\r\n");
    free(words);
    free(answer);
    return 0;
}


Python Solution: github

#coding=utf-8

'''
    url: leetcode.com/problems/substring-with-concatenation-of-all-words/
    @author:     zxwtry
    @email:      zxwtry@qq.com
    @date:       2017年4月1日
    @details:    Solution: 82ms 93.41%
'''

class Solution(object):
    def findSubstring(self, s, w):
        """
        :type s: str
        :type w: List[str]
        :rtype: List[int]
        """
        wn = 0 if w == None else len(w)
        sn = 0 if s == None else len(s)
        #return invalid
        if wn == 0 or sn < sn:
            return []
        ans, wl, wm, sm = [], len(w[0]), {}, {}
        for i in range(wn):
            if w[i] in wm:
                wm[w[i]] += 1
            else: wm[w[i]] = 1
        for i in range(wl):
            sm.clear()
            ii = i
            cnt = 0
            for j in range(i, sn, wl):
                ss = s[j: j + wl]
                #continue ss not in wm
                #clear all record
                if not ss in wm:
                    sm.clear()
                    ii = j + wl
                    cnt = 0
                    continue
                #complete add ss to sm
                if ss in sm:
                    sm[ss] += 1
                else:sm[ss] = 1
                cnt += 1
                #check add valid
                while sm[ss] > wm[ss]:
                    sm[s[ii: ii + wl]] -= 1
                    ii += wl
                    cnt -= 1
                if cnt == wn:
                    ans.append(ii)
        return ans
        
if __name__ == "__main__":
    s = "barfoofoobarthefoobarman"
    w = ["bar","foo","the"]
    print(Solution().findSubstring(s, w))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值