Ok, this is an interview question. And no it's not a duplicate of this question.
Given 3 strings - str1
, str2
, str3
:
str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
We've to find the minimum window in str1
, which contains all characters from str2
in any order, but no character from str3
. In this case the answer would be: "strup"
.
I've come up with this code:
static String minimumWindow(String str1, String str2, String str3) {
class Window implements Comparable<Window> {
int start;
int end;
public Window(int start, int end) {
this.start = start;
this.end = end;
}
public int getEnd() {
return end;
}
public int getStart() {
return start;
}
public int compareTo(Window o) {
int thisDiff = end - start;
int thatDiff = o.end - o.start;
return Integer.compare(thisDiff, thatDiff);
}
@Override
public String toString() {
return "[" + start + " : " + end + "]";
}
}
// Create Sets of characters for "contains()" check
Set<Character> str2Chars = new HashSet<>();
for (char ch: str2.toCharArray()) {
str2Chars.add(ch);
}
Set<Character> str3Chars = new HashSet<>();
for (char ch: str3.toCharArray()) {
str3Chars.add(ch);
}
// This will store all valid window which doesn't contain characters
// from str3.
Set<Window> set = new TreeSet<>();
int begin = -1;
// This loops gets each pair of index, such that substring from
// [start, end) in each window doesn't contain any characters from str3
for (int i = 0; i < str1.length(); i++) {
if (str3Chars.contains(str1.charAt(i))) {
set.add(new Window(begin, i));
begin = i + 1;
}
}
int minLength = Integer.MAX_VALUE;
String minString = "";
// Iterate over the windows to find minimum length string containing all
// characters from str2
for (Window window: set) {
if ((window.getEnd() - 1 - window.getStart()) < str2.length()) {
continue;
}
for (int i = window.getStart(); i < window.getEnd(); i++) {
if (str2Chars.contains(str1.charAt(i))) {
// Got first character in this window that is in str2
// Start iterating from end to get last character
// [start, end) substring will be the minimum length
// string in this window
for (int j = window.getEnd() - 1; j > i; j--) {
if (str2Chars.contains(str1.charAt(j))) {
String s = str1.substring(i, j + 1);
Set<Character> sChars = new HashSet<>();
for (char ch: s.toCharArray()) {
sChars.add(ch);
}
// If this substring contains all characters from str2,
// then only it is valid window.
if (sChars.containsAll(str2Chars)) {
int len = sChars.size();
if (len < minLength) {
minLength = len;
minString = s;
}
}
}
}
}
}
}
// There are cases when some trailing and leading characters are
// repeated somewhere in the middle. We don't need to include them in the
// minLength.
// In the given example, the actual string would come as - "rstrup", but we
// remove the first "r" safely.
StringBuilder strBuilder = new StringBuilder(minString);
while (strBuilder.length() > 1 && strBuilder.substring(1).contains("" + strBuilder.charAt(0))) {
strBuilder.deleteCharAt(0);
}
while (strBuilder.length() > 1 && strBuilder.substring(0, strBuilder.length() - 1).contains("" + strBuilder.charAt(strBuilder.length() - 1))) {
strBuilder.deleteCharAt(strBuilder.length() - 1);
}
return strBuilder.toString();
}
But it doesn't work for all the test cases. It does work for the example given in this question. But when I submitted the code, it failed for 2 test cases. No I don't know the test cases for which it failed.
Even after trying various sample inputs, I couldn't find a test case for which it fails. Can someone take a look as to what is wrong with the code? I would really appreciate if someone can give a better algorithm (Just in pseudo-code). I know this is really not the optimized solution though.
Minimum Window Substring. Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "" .
To locate a substring in a string, use the indexOf() method. Let's say the following is our string. String str = "testdemo"; Find a substring 'demo' in a string and get the index.
str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
We're looking for the minimum sub-string from str1
that contain all str2
characters (assume ordered) and no characters from str3
..
i = 1 .. str1.length
cursor = 1 .. str2.length
The solution must be on the form:
str2.first X X .. X X str2.last
So to check for that sub-string we use a cursor over str2
, but we also have the constraint of avoiding str3
characters, so we have:
if str3.contain(str1[i])
cursor = 1
else
if str1[i] == str2[cursor]
cursor++
Goal check is:
if cursor > str2.length
return solution
else
if i >= str1.length
return not-found
And for optimization, you can skip to the next look-ahead which is:
look-ahead = { str2[cursor] or { X | X in str3 }}
In case str2
is not ordered:
i = 1 .. str1.length
lookup = { X | X in str2 }
The solution must be on the form:
str2[x] X X .. X X str2[x]
So to check for that sub-string we use a check-list str2
, but we also have the constraint of avoiding str3
characters, so we have:
if str3.contain(str1[i])
lookup = { X | X in str2 }
else
if lookup.contain(str1[i])
lookup.remove(str1[i])
Goal check is:
if lookup is empty
return solution
else
if i >= str1.length
return not-found
And for optimization, you can skip to the next look-ahead which is:
look-ahead = {{ X | X in lookup } or { X | X in str3 }}
Code
class Solution
{
private static ArrayList<Character> getCharList (String str)
{
return Arrays.asList(str.getCharArray());
}
private static void findFirst (String a, String b, String c)
{
int cursor = 0;
int start = -1;
int end = -1;
ArrayList<Character> stream = getCharList(a);
ArrayList<Character> lookup = getCharList(b);
ArrayList<Character> avoid = getCharList(c);
for(Character ch : stream)
{
if (avoid.contains(ch))
{
lookup = getCharList(b);
start = -1;
end = -1;
}
else
{
if (lookup.contains(ch))
{
lookup.remove(ch)
if (start == -1) start = cursor;
end = cursor;
}
}
if (lookup.isEmpty())
break;
cursor++;
}
if (lookup.isEmpty())
{
System.out.println(" found at ("+start+":"+end+") ");
}
else
{
System.out.println(" not found ");
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With