您的位置:首页 > 其它

leetcode hard模式专杀之76 Minimum Window Substring

2017-06-05 13:10 495 查看
继续刷leetcode hard模式 https://leetcode.com/problems/minimum-window-substring/#/description

这题感觉算是hard模式中比较容易的 一题, 不过算法非常典型, 是一个举一反三的好例子, 很多看起来很难的题目都可以通过这题找到原始思路。

按说找一个字符串窗口不是难事,但是要保持O(n)的时间复杂度,就要稍微考虑考虑了,另外题目有一点没有表述清楚,就是重复字符到底怎么算,我是直到跑了OJ之后才知道它这个题目的本意是要把重复的字符当成多个而非一个的,例如aa就是两个a,不能按照一个a来算。

那么思路其实是这样,从i到maxIndex进行循环,这里用maxIndex而不是s.length-1是为了减少循环次数,因为可以明显知道最后面几个index是不可能包含我们需要的结果的。

这个循环本身就是O(n)了,那要整个计算程序保持在O(n)的时间复杂度看起来是一件不可能的事情,我觉得理论上的确是不太可能,不过我用如下的方法竟然通过了OJ, 好吧,说说思路吧。

用两个变量left和right,分别标记窗口左端和右端, 一开始都初始化为0,然后right开始往右移动,直到窗口中包含了所有需要的字符,至于如何判断是否包含了所有需要的字符,可以用两个hashmap来判断, 简单来说key是需要包含的字符,value是字符出现的次数。一旦right找到这么一个位置之后,开始尝试收缩左边窗口,也就是增加left,  一直收缩到不再包含需要的所有字符串,则left的一个位置就是本次循环最小的位置,然后继续增加右窗口,直到在此包含所有需要的位置,然后继续尝试收缩左边的窗口,这样循环走下去之后,就可以找到最小的窗口长度以及起始位置,如果找不到这样的位置,则返回"",
好了,上代码:

public class Solution {
public boolean compareMap(Map<String,Integer> mp1, Map<String, Integer> mp2){
for(String keyInMp1: mp1.keySet()){
if(mp2.get(keyInMp1)==null || mp2.get(keyInMp1)<mp1.get(keyInMp1)){
return false;
}
}
return true;
}
public String minWindow(String s, String t) {
int left = 0;
int right = 0;

Map<String, Integer> dict = new HashMap();
// initialize dict
for(int i = 0; i<t.length(); i++){
if(dict.containsKey(t.substring(i,i+1))){
dict.put(t.substring(i,i+1), dict.get(t.substring(i,i+1))+1);
}else{
dict.put(t.substring(i,i+1), 1);
}
}

int minwindowsize = s.length();
int startIndex = 0;

boolean touched = false;
for(left = 0; left<=s.length()-dict.keySet().size(); left++){
Map<String, Integer> curDict = new HashMap();
while(right<s.length()){
if(dict.containsKey(s.substring(right, right+1))){
if(curDict.containsKey(s.substring(right, right+1))){
curDict.put(s.substring(right, right+1), curDict.get(s.substring(right, right+1))+1);
}else{
curDict.put(s.substring(right, right+1),1);
}
if(compareMap(dict, curDict)){
touched = true;
//window match, compare with the previous minium size and update if window size is smaller
if(right-left+1<minwindowsize){
startIndex = left;
minwindowsize = right-left+1;
}
// try to shrink the left until the minimum length that contains all chars we need
while(compareMap(dict, curDict)){
String toRemove = s.substring(left, left+1);
if(right-left+1<minwindowsize){
startIndex = left;
minwindowsize = right-left+1;
}
left++;
if(curDict.get(toRemove)==null){
continue;
}else if(curDict.get(toRemove)!=null && curDict.get(toRemove)>1){
curDict.put(toRemove, curDict.get(toRemove)-1);
}else if(curDict.get(toRemove)==1){
curDict.remove(toRemove);
}
}
}
}
right++;
}
}
if(touched==false){
return "";
}else{
return s.substring(startIndex, startIndex+minwindowsize);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: