字符串1中的最小窗口包含字符串2中的所有字符,而字符串3中没有字符

Roh*_*ain 6 java language-agnostic string algorithm

好的,这是一个面试问题.不,这不是这个问题的重复.

鉴于3串- ,str1,:str2str3

str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
Run Code Online (Sandbox Code Playgroud)

我们要找到最小窗口str1,其中包含str2任何顺序的所有字符,但不包含任何字符str3.在这种情况下,答案是:"strup".

我想出了这段代码:

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();
    }
Run Code Online (Sandbox Code Playgroud)

但它并不适用于所有测试用例.它确实适用于此问题中给出的示例.但是当我提交代码时,它失败了2个测试用例.不,我不知道它失败的测试用例.

即使在尝试了各种样本输入之后,我也找不到它失败的测试用例.有人可以看看代码有什么问题吗?如果有人可以提供更好的算法(仅使用伪代码),我将非常感激.我知道这不是优化的解决方案.

Kha*_*d.K 2

str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
Run Code Online (Sandbox Code Playgroud)

str1我们正在寻找包含所有str2字符(假设有序)并且不包含 .. 中的字符的最小子字符串str3

i = 1 .. str1.length
cursor = 1 .. str2.length
Run Code Online (Sandbox Code Playgroud)

解决方案必须采用以下形式:

str2.first X X .. X X str2.last
Run Code Online (Sandbox Code Playgroud)

因此,为了检查该子字符串,我们使用光标悬停在 上str2,但我们也有避免字符的约束str3,所以我们有:

if str3.contain(str1[i])
    cursor = 1
else
    if str1[i] == str2[cursor]
        cursor++
Run Code Online (Sandbox Code Playgroud)

目标检查是:

if cursor > str2.length
    return solution
else
    if i >= str1.length
        return not-found
Run Code Online (Sandbox Code Playgroud)

为了优化,您可以跳到下一个预测,即:

look-ahead = { str2[cursor] or { X | X in str3 }}
Run Code Online (Sandbox Code Playgroud)

如果str2订购

i = 1 .. str1.length
lookup = { X | X in str2 }
Run Code Online (Sandbox Code Playgroud)

解决方案必须采用以下形式:

str2[x] X X .. X X str2[x]
Run Code Online (Sandbox Code Playgroud)

因此,为了检查该子字符串,我们使用检查列表str2,但我们也有避免字符的约束str3,所以我们有:

if str3.contain(str1[i])
    lookup = { X | X in str2 }
else
    if lookup.contain(str1[i])
        lookup.remove(str1[i])
Run Code Online (Sandbox Code Playgroud)

目标检查是:

if lookup is empty
    return solution
else
    if i >= str1.length
        return not-found
Run Code Online (Sandbox Code Playgroud)

为了优化,您可以跳到下一个预测,即:

look-ahead = {{ X | X in lookup } or { X | X in str3 }}
Run Code Online (Sandbox Code Playgroud)

代码

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 ");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)