1
+ package SubstringwithConcatenationofAllWords ;
2
+
3
+ import java .util .*;
4
+ import java .util .stream .Collectors ;
5
+ import java .util .stream .Stream ;
6
+
7
+ /**
8
+ * User: Danyang
9
+ * Date: 1/29/2015
10
+ * Time: 10:05
11
+ *
12
+ * You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of
13
+ * substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
14
+
15
+ For example, given:
16
+ S: "barfoothefoobarman"
17
+ L: ["foo", "bar"]
18
+
19
+ You should return the indices: [0,9].
20
+ (order does not matter).
21
+ */
22
+ public class Solution {
23
+ /**
24
+ * https://github.com/zhangdanyangg/LeetCode/blob/master/029%20Substring%20with%20Concatenation%20of%20All%20Words.py
25
+ *
26
+ * Algorithm:
27
+ * Two pointers, sliding window, O(n*k)
28
+ *
29
+ * Notice:
30
+ * 1. equal length
31
+ * 2. when fail finding word, i need to go back to beginning
32
+ * @param S
33
+ * @param L
34
+ * @return
35
+ */
36
+ public List <Integer > findSubstring (String S , String [] L ) {
37
+ List <Integer > ret = new ArrayList <>();
38
+ if (L .length <1 || S .length ()<1 )
39
+ return ret ;
40
+
41
+ Map <String , Long > Lmap_origin = Stream .of (L ).collect (
42
+ Collectors .groupingBy (e -> e , Collectors .counting ())
43
+ );
44
+
45
+ Map <String , Long > Lmap = new HashMap <>(Lmap_origin ); // copy constructor
46
+ List <String > workingWin = new ArrayList <>();
47
+
48
+ int i = 0 ;
49
+ int k = L [0 ].length ();
50
+ int win_e = -1 ;
51
+ while (i <S .length ()) {
52
+ if (workingWin .size ()==L .length ) {
53
+ ret .add (win_e -workingWin .size ()*k );
54
+ int next = win_e -workingWin .size ()*k +1 ;
55
+ if (Lmap .containsKey (S .substring (next , Math .min (next +k , S .length ())))) {
56
+ i = next ;
57
+ workingWin .clear ();
58
+ win_e = -1 ;
59
+ Lmap = new HashMap <>(Lmap_origin );
60
+ continue ;
61
+ }
62
+ }
63
+
64
+
65
+ String word = S .substring (i , Math .min (i +k , S .length ()));
66
+ if (!Lmap .containsKey (word )) {
67
+ if (workingWin .isEmpty ())
68
+ i ++;
69
+ else
70
+ i = win_e -workingWin .size ()*k +1 ;
71
+ workingWin .clear ();
72
+ win_e = -1 ;
73
+ Lmap = new HashMap <>(Lmap_origin );
74
+ }
75
+ else if (Lmap .get (word )>0 ) { // found remain
76
+ win_e = i +k ;
77
+ Lmap .put (word , Lmap .get (word )-1 );
78
+ workingWin .add (word );
79
+ i = win_e ;
80
+ }
81
+ else {
82
+ int indexOf = workingWin .indexOf (word );
83
+ for (int j =0 ; j <=indexOf ; j ++) {
84
+ String word2 = workingWin .get (j );
85
+ Lmap .put (word2 , Lmap .get (word2 )+1 );
86
+ }
87
+ win_e = i +k ;
88
+ Lmap .put (word , Lmap .get (word )-1 );
89
+ workingWin = workingWin .subList (indexOf +1 , workingWin .size ());
90
+ workingWin .add (word );
91
+ i = win_e ;
92
+ }
93
+ }
94
+ if (workingWin .size ()==L .length ) // when reaching end: test case Input: "a", ["a"]
95
+ ret .add (win_e -workingWin .size ()*k );
96
+ return ret ;
97
+ }
98
+
99
+ public static void main (String [] args ) {
100
+ List <Integer > ret = new Solution ().findSubstring ("aaaaaaaa" , new String []{"aa" , "aa" , "aa" });
101
+ List <Integer > expected = Arrays .asList (new Integer []{0 , 1 , 2 });
102
+ assert ret .equals (expected );
103
+ }
104
+ }
0 commit comments