`
frank-liu
  • 浏览: 1682141 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

leetcode: Minimum Window Substring

 
阅读更多

问题描述:

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"

Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

原问题链接:https://leetcode.com/problems/minimum-window-substring/

 

问题分析

  这个问题相对比较复杂,主要是对于给定窗口的值和目标值之间的比较匹配和最小窗口的判断。这里结合这两个点来讨论。

  首先一个,对于给定的一个源串来说,我怎么知道其中的某一段就包含了目标串里所有的字符呢?尤其是在一个串里还可能有多次重复的元素。一个基本的思路是,我们首先遍历目标串,将它里面每个字符和字符出现的次数都映射保存到一个map里。这样就有了一个保存和比较的基础。对于源串来说,每遍历遇到一个元素的时候就要和目标串建立的map进行比较。可是怎么确保源串的部分正好就涵盖了目标串的所有字符呢?如果每碰到一个就对原来的map里对应的元素减一的话,这样还是不能保证恰好都涵盖了所有的。一种思路是我们用一个变量count来记录目标串的长度。每次在遍历源串的时候,碰到的字符在目标串里存在的,而且在源串里出现的次数小于等于目标串里出现的次数,我们就对count加一。这样直到最后count的值和目标串的长度相等。我们就肯定可以确定,前面这一段是已经涵盖目标串了。

  解决了第一个问题之后,下一个问题就是怎么找到最小的窗口呢?这个时候我们就需要从源串的开头去再次遍历这个串。在碰到一个存在于目标串中的元素时,这个位置才可能是窗口的开头。这样就跳过了一些在目标串中不存在的元素。但是这样做还是不够充分的。还有一种情况就是我们遍历过的某一段字符串它里面有些在目标串里也存在的字符出现的次数比目标串里出现的次数还要多。这个时候对于这些存在于源串中但是出现次数更多的情况,我们是可以继续将字符串的位置往后面移的,因为这样肯定保证了串包含了给定的目标串内容,同时也尽量缩小了串的长度。

  按照这个思路,我们在具体的实现里用了两个map,一个用来保存目标串t里所有字符和出现的次数。另外一个用来记录遍历源串s时在目标串中出现的字符和次数。我们一边遍历s的时候一边记录符合条件的元素的个数。在发现符合条件的字符串长度达到给定长度时则从头开始进行最小窗口的判断。每次比较后将最小窗口的开始和结束位置保存下来。还有一个情况就是在源串里根本就不可能包含有目标串所有的字符,这里具体的实现就是通过判断位置元素l是否为-1。因为一旦有符合条件的串,l必然参加比较,它也将会被赋值。详细代码实现如下:

 

public class Solution {
    public String minWindow(String s, String t) {
        if(s.isEmpty() || t.isEmpty()) return "";
        Map<Character, Integer> itemsFound = new HashMap<>();
        Map<Character, Integer> toBeFound = new HashMap<>();
        int count = 0, minLen = Integer.MAX_VALUE, l = -1, r = -1;
        for(int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            if(toBeFound.containsKey(c))
                toBeFound.put(c, toBeFound.get(c) + 1);
            else toBeFound.put(c, 1);
        }
        for(int start = 0, end = 0; end < s.length(); end++) {
            char e = s.charAt(end);
            if(!toBeFound.containsKey(e)) continue;
            if(itemsFound.containsKey(e))
                itemsFound.put(e, itemsFound.get(e) + 1);
            else itemsFound.put(e, 1);
            if(itemsFound.get(e) <= toBeFound.get(e)) count++;
            if(count == t.length()) {
                char ch = s.charAt(start);
                while(!toBeFound.containsKey(ch) || itemsFound.get(ch) > toBeFound.get(ch)) {
                    if(toBeFound.containsKey(ch) && itemsFound.get(ch) > toBeFound.get(ch)) 
                        itemsFound.put(ch, itemsFound.get(ch) - 1);
                    start++;
                    ch = s.charAt(start);
                }
                if(end - start < minLen) {
                    minLen = end - start;
                    l = start;
                    r = end;
                }
            }
        }
        return l == -1 ? "" : s.substring(l, r + 1);
    }
}

  这个方法实现的时间复杂度为O(N)。在实际执行的结果里我们会发现它的效率并不是很高。因为这里用的map保存的数据类型和字符串里的char类型等需要进行类型的boxing和unboxing,它在很大程度上拖累了性能。在有的实现里将两个串首先转换成纯字符数组然后再进行统计比较,这样可以极大的提高系统执行的效率。

 

参考材料

http://articles.leetcode.com/finding-minimum-window-in-s-which/ 

分享到:
评论

相关推荐

    leetcode分类-leetcode:leetcode

    leetcode 分类 Leetcode Introduction 本文旨在将leetcode的题型分类 Pattern: Sliding window 滑动窗口类型的题目经常是用来执行数组或是链表上某个区间(窗口)上的操作。比如找最长的全为1的子数组长度。滑动窗口...

    leetcode76-LeetCode76_MinimumWindowSubstring:LeetCode76_MinimumWindowSu

    标题 "LeetCode76-LeetCode76_MinimumWindowSubstring:LeetCode76_MinimumWindowSu" 指向的是一个关于LeetCode第76题的解决方案。这道题目要求找到一个给定字符串中最小子串,该子串包含了另一个给定的字符集(目标...

    dna匹配leetcode-leetcode:leetcode刷题

    Minimum Window Substring 两个指针遍历 map Maximal Rectangle 栈 局部递增 或者 动态规划 Binary Tree Inorder Traversal 栈 递归 Single Number 异或 Copy List with Random Pointer 单链表 map Max Points on a ...

    leetcode添加元素使和等于-leetcode:我的leetcode解决方案

    leetcode添加元素使和等于 经验教训 一定要吧功能尽量细化为函数,这样一者做题思路比较清晰,二者可以在某些情况下直接return值。 如果输入的形式是一个序列,则可以想想:分治、动规、贪婪,一般不建议搜索,因为...

    python-leetcode题解之076-Minimum-Window-Substring

    python python_leetcode题解之076_Minimum_Window_Substring

    c语言-leetcode题解之0076-minimum-window-substring.zip

    c c语言_leetcode题解之0076_minimum_window_substring.zip

    js-leetcode题解之76-minimum-window-substring.js

    javascript js_leetcode题解之76-minimum-window-substring.js

    LeetCode最全代码

    411 | [Minimum Unique Word Abbreviation](https://leetcode.com/problems/minimum-unique-word-abbreviation/) | [C++](./C++/minimum-unique-word-abbreviation.cpp) [Python](./Python/minimum-unique-word-...

    _leetcode-python.pdf

    - Minimum Window Substring: 给定两个字符串s和t,找出s中包含t所有字母的最小子串。 - Remove Duplicates from Sorted Array II: 删除排序数组中的重复项,使得每个元素最多出现两次。 - Search in Rotated Sorted...

    c++-c++编程基础之leetcode题解第76题最小覆盖子串.zip

    第76题"最小覆盖子串"(Minimum Window Substring)是其中一道经典的字符串处理问题,它涉及到字符串查找、滑动窗口等算法概念。在这个题解压缩包中,你将找到关于如何使用C++解决这道题目的详细步骤和代码实现。 ...

    1、基础算法必练题(含解法)).pdf

    12. **Minimum Window Substring** (Hard): 寻找包含所有给定字符的最小子串。使用双指针和滑动窗口优化搜索过程。 13. **Merge Two Sorted Lists** (Easy): 合并两个已排序的链表。可以通过迭代或递归方法解决,...

Global site tag (gtag.js) - Google Analytics