LeetCode_OJ【76】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.


这题也是看了题目提示才有的思路,题目的提示是:hashtable, two pointer.

我们可以用哈希表来保存模式串中各个字符出现的次数;

然后用双指针法遍历主串:

1)开始时low和high都指向主串第一个字符(此时[low,high)子串为空);

2)high向后移动,直到[low,high)包含模式串所需要的所有字符。

3)low向后移动,直到[low,high)不能完全包含模式串所需要的所有字符,转到2)

high指向主串最后一个字符的后面,且[low,high)不能完全包含模式串所需要的所有字符时停止算法。

这里我们使用count变量来标识[low,high)是否能够完全包含模式串所需要的所有字符,count最开始标识模式串中字符的个数,,high向后移动时,若包含一个模式串的字符,count减1,同时修改哈希表;low向后移动时,若比原来少包含一个模式串的字符,count加1,同时修改哈希表。 这样我们就可以通过count是否等于0 来判断[low,high)是否能够完全包含模式串所需要的所有字符。

以下是JAVA实现,用到了HashMap,最后leetcode跑出来的性能只比42.5%的提交要好,我觉得可能是别人使用了数组来表示哈希表,有时间再实现下数组的版本。

public class Solution {
    public String minWindow(String s, String t) {
		int count = 0 ; 
		HashMap<Character,Integer> hash = new HashMap<Character, Integer>();
		for(int i = 0 ; i < t.length() ; i ++){
			if(hash.containsKey(t.charAt(i)))
				hash.put(t.charAt(i), hash.get(t.charAt(i)) +1);
			else
				hash.put(t.charAt(i), 1);
			count ++;
		}
		int start = 0,end = 0,min = s.length() +1; //存储结果;
		int low = 0,high = 0; //指针
		while(!(high == s.length() && count > 0 )){   //high走到底(因为左闭右开,所以high可以取到length),但是count仍大于0时停止
			if(count > 0 ){
				high ++;
				if(hash.containsKey(s.charAt(high-1))){
					if(hash.get(s.charAt(high -1)) > 0)
						count --;
					hash.put(s.charAt(high -1), hash.get(s.charAt(high -1)) -1);
				}
			}
			else{
				if(high - low < min){
					min = high - low;
					start = low;
					end = high;
				}
				low ++ ;
				if(hash.containsKey(s.charAt(low-1))){
					hash.put(s.charAt(low -1), hash.get(s.charAt(low -1)) +1);
					if(hash.get(s.charAt(low -1)) > 0)
						count ++;
				}	
			}
		}
		return s.substring(start,end);
    }
}

下午实现了一下数组版本的,该版本超过了93%的java提交,具体如下:声明两个数组,分别表示某字符在模式串中是否存在以及数量;这里使用两个数组是因为后面再遍历主串的时候需要修改保存数量的数组,数组中的值会出现为负的情况,所以不能单纯地以是否是负数来区别该字符在模式串中是否出现过。

public class Solution {
    public String minWindow(String s, String t) {
		int count = 0 ; 
		int[] contain = new int[256];
		int[] nums = new int[256];
		for(int i = 0 ; i < t.length() ; i ++){
			if(contain[t.charAt(i)] == 0)
				contain[t.charAt(i)] = 1;
			nums[t.charAt(i)] ++ ;
			count ++;
		}
		int start = 0,end = 0,min = s.length() +1; //存储结果;
		int low = 0,high = 0; //指针
		while(!(high == s.length() && count > 0 )){   //high走到底(因为左闭右开,所以high可以取到length),但是count仍大于0时停止
			if(count > 0 ){
				high ++;
				if(contain[s.charAt(high-1)] > 0){
					if(nums[s.charAt(high -1)] > 0)
						count --;
					nums[s.charAt(high -1)] --;
				}
			}
			else{
				if(high - low < min){
					min = high - low;
					start = low;
					end = high;
				}
				low ++ ;
				if(contain[s.charAt(low-1)] > 0){
					nums[s.charAt(low-1)] ++;
					if(nums[s.charAt(low-1)] > 0)
						count ++;
				}	
			}
		}
		return s.substring(start,end);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值