-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFindAllAnagramsInString.java
More file actions
135 lines (111 loc) · 5.41 KB
/
FindAllAnagramsInString.java
File metadata and controls
135 lines (111 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package Algorithms.SlidingWindow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* <pre>
* We already know, how brute force works. Here just focus on O(n) algorithm
*
* CONSTRAINTS:
* 1. s and p chars are lowercase english letters
*
* </pre>
* @author Srinivas Vadige, srinivas.vadige@gmail.com
* @since 29 Sept 2024
*/
public class FindAllAnagramsInString {
public static void main(String[] args) {
String s = "cbaebabacd", p = "abc";
// String s = "abab", p = "ab";
System.out.println("findAnagrams : " + findAnagrams(s, p));
System.out.println("findAnagramsDoResearch : " + findAnagramsDoResearch(s, p) + " --- wrong ans" );
}
public static List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new ArrayList<>();
int[] markArr = new int[26];
int left=0, right=0, found=0;
for(char c: p.toCharArray())
markArr[c-'a']++;
while (right<s.length()) {
if(markArr[s.charAt(right++)-'a']-- >= 1) found++;
if(found==p.length()) list.add(left);
if(right - left == p.length() && markArr[s.charAt(left++)-'a']++ >= 0) found--;
}
return list;
}
/**
* This is exactly same findAnagrams() logic but explained the each step in detailed
*
* Note that mark or visit means decreasing the char count in markArr
* and similarly to unmark or revist means increasing back the char count in the markArr
*/
public static List<Integer> findAnagramsExplained(String s, String p) {
List<Integer> list = new ArrayList<>();
int[] markArr = new int[26]; // for both p&s chars as the both chars are lowercase english letters or we can use Map<Character, Integer> instead
int left=0, right=0, found=0;
// PREPARE CHAR ARRAY WITH P CHARS AS DEFAULT
for(char c: p.toCharArray())
markArr[c-'a']++; // 'a' is char i.e ascii value and c-'a' means char-65 Eg: 'a'-'a' => 0 as 65-65=0
while (right<s.length()) {
System.out.println(s.substring(left, right+1));
// IS RIGHT S CHAR IS IN P? --- check before marking the right char in markArr and before incresing the right pointer
if(markArr[s.charAt(right) - 'a'] >= 1) // p char in right pointer s chars is always >=1 as we unmark every char in WINDOW LENGTH condition
found++;
markArr[s.charAt(right) - 'a']--; // mark right index visited char
right++;
// if(markArr[s.charAt(right++)-'a']-- >= 1) found++; //// i.e instead of these 4 lines, simply use if(markArr[s.charAt(right++)-'a']-- >= 1) found++; --- i.e 1st array num-- and then right++
// FOUND ALL P CHARS IN S
if(found==p.length()) list.add(left);
// WINDOW LENGTH --- i.e left pointer waits till the right reaches the 1st window length and this window length will continue through out the loop as we check each and every char in s
if(right - left == p.length()){
// IS CURRENT LEFT S CHAR IS IN P? --- check before unmarking the left char in markArr and before increasing the left pointer
if(markArr[s.charAt(left) - 'a'] >=0 ) // p char in left pointer s chars is always >=0 as we unmark every char below
found--;
markArr[s.charAt(left) - 'a']++; // unmark left index visited char, because we already marked the char with right index
left++;
}
// if(right - left == p.length() && markArr[s.charAt(left++)-'a']++ >= 0) found--; //// i.e instead of these 6 lines, simply use if(right - left == p.length() && markArr[s.charAt(right++)-'a']-- >= 0) found--; i.e 1st arr num++ and then right++
}
return list;
}
/**
* ---- my thoughts --- need to research more
* @Intuition - p is window length and we can use left and right pointers with sliding
*
* <p> but gettting TLE
*/
@SuppressWarnings("unused")
public static List<Integer> findAnagramsDoResearch(String s, String p) {
List<Integer> list = new ArrayList<>();
if(s.length() < p.length()) return list;
int left=0, right=0;
Map<Character, Integer> pMap = p.chars().mapToObj(i->(char)i).collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e->1)));
Map<Character, Integer> temMap = new HashMap<>(pMap);
int TARGET_WINDOW = p.length();
int found = 0;
while(right<s.length()) {
if(temMap.getOrDefault(s.charAt(right), -1) > 0 && found <= TARGET_WINDOW ){
found++;
temMap.merge(s.charAt(right), -1, Integer::sum);
}
if(found == TARGET_WINDOW){
left = right+1-TARGET_WINDOW;
list.add(left);
//System.out.println(s.substring(left, right+1));
}
if(temMap.getOrDefault(s.charAt(right), -1) < 0 || found > TARGET_WINDOW ){
found = 0;
temMap = new HashMap<>(pMap);
}
// if(temMap.getOrDefault(s.charAt(right), -1) == 0 && found == TARGET_WINDOW){
// found++;
// temMap.merge(s.charAt(right), -1, Integer::sum);
// }
right++;
}
return list;
}
}