Leetcode 76 Minimum Window Substring 最小覆盖子串,最小移动窗口

这道题,刚开始拿到的时候,自己是没有思路的,然后自己尝试着去写,错的多了,也就有思路了,但是超时了,于是看看别人使用的什么办法。嘿嘿

题目:

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

说明:

  • 如果 S 中不存这样的子串,则返回空字符串 ""
  • 如果 S 中存在这样的子串,我们保证它是唯一的答案。

首先看下我的超时代码,但是正确的。

package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LC76Try1
{
	public String minWindow(String s, String t)
	{
		String ret = "";
		int ls = s.length();
		int lt = t.length();
		if (ls < lt)
		{
			return "";
		}
		Map<String, Integer> map = new HashMap<String, Integer>();
		Map<String,List<Integer>> dp = new HashMap<String, List<Integer>>();
		int[] ans=new int[ls];
		//查看各个元素出现的次数
		for(int i=0;i<lt;i++){
			String st=String.valueOf(t.charAt(i));
			if(map.containsKey(st)){
				Integer count=map.get(st);
				map.put(st, count+1);
			}else{
				map.put(st, 1);
			}
		}
		//初始dp,dp【key,list】,其中s中和key相同的下坐标
		for(int j=0;j<lt;j++){
			String s1=String.valueOf(t.charAt(j));
			char c1=t.charAt(j);
			if(dp.containsKey(s1)){				
				continue;
			}else{				
				List<Integer> list =new ArrayList<Integer>();
				for(int k=0;k<ls;k++){
					char c2=s.charAt(k);
					if(c1==c2){
						list.add(k);
					}
				}
				if(list.size()==0){
					return "";
				}else{
					dp.put(s1, list);
				}
			}
		}
		//ans【i】记录的就是从i开始的最小窗口
		for(int i=0;i<ls;i++){
			String s2=String.valueOf(s.charAt(i));
			if(map.containsKey(s2)){
				int max=-1;
				for(String s3 :map.keySet()){
					 Integer count = map.get(s3);
					 List<Integer> l2=dp.get(s3);
					 int temp=0;
					 for(int j=0;j<l2.size();j++){
						 if(l2.get(j)>=i){
							 temp++;
							 if(temp==count){
								 if(l2.get(j)>max){
									 max=l2.get(j);
								 }
								 break;
							 }
						 }
					 }
					 if(temp<count){
						 max=-1;
						 break;
					 }
					 
				}
				ans[i]=max;
				
				
			}else{
				ans[i]=-1;
				continue;
			}
		}
		int x=0;
		int y=-1;
		int min=ls;
		//遍历所有的窗口,找到最小的
		for(int i=0;i<ls;i++){		
			if(ans[i]==-1){
				continue;
			}else{
				if(ans[i]-i<min){
					min=ans[i]-i;
					x=i;
					y=ans[i];
				}
			}
		}
		ret=s.substring(x,y+1);
		return ret;

	}

	public static void main(String[] args)
	{
		LC76Try1 t = new LC76Try1();
		String ret = t.minWindow("a", "");
		System.out.println(ret);

	}

}

然后,我就看了这位的博客,我觉得人家讲的蛮好的。很容易理解。https://blog.csdn.net/u013115610/article/details/70257445,防止他的丢了,我用的人家的图

思路:采用滑动窗口,窗口有左右边界,先通过扩展右边界找出一个包含T中所有字符的子串,然后收缩左边界,直到不能再收缩。记录此时的子串。然后收缩左边界,继续扩展右边界,直到再找到满足要求的子串,和上次的进行比较,保存更小的子串。返回执行,直到右边界到达S串尾,且左边界不能再收缩。


代码:还是我自己写吧:貌似时间还是比较慢:

package test;

import java.util.HashMap;
import java.util.Map;

public class LC76Try2
{
	public String minWindow(String s, String t)
	{
		String ret = "";
		int ls = s.length();
		int lt = t.length();
		if (ls < lt)
		{
			return "";
		}
		Map<Character, Integer> map = new HashMap<Character, Integer>();
		for (int i = 0; i < lt; i++)
		{
			char c1 = t.charAt(i);
			if (map.containsKey(c1))
			{
				Integer count = map.get(c1);
				map.put(c1, count + 1);
			}
			else
			{
				map.put(c1, 1);
			}
		}
		int left = 0;
		int cn = 0;
		int x = 0;
		int y = -1;
		int min = ls;
		for (int right = 0; right < ls; right++)
		{
			char c2 = s.charAt(right);
			if (map.containsKey(c2))
			{
				Integer tn = map.get(c2);
				tn--;
				if (tn >= 0)
				{
					cn++;
				}
				map.put(c2, tn);
			}
			while (cn == lt)
			{
				if (right - left < min)
				{
					min = right - left;
					x = left;
					y = right;
				}
				c2 = s.charAt(left);
				if (map.containsKey(c2))
				{
					if (map.get(c2) >= 0)
					{
						cn--;
					}
					Integer tn = map.get(c2);
					tn++;
					map.put(c2, tn);

				}
				left++;
			}
			

		}
        ret=s.substring(x,y+1);
		return ret;

	}
	public static void main(String[] args)
	{
		LC76Try2 t = new LC76Try2();
		String ret = t.minWindow("a", "a");
		System.out.println(ret);

	}

}

更快的,不用map的,代码:

package test;

public class LC76Try3
{
	public String minWindow(String s, String t)
	{
		int start = 0, minLen = Integer.MAX_VALUE;
		int left = 0;
		int[] map = new int[256];
		int count = t.length();

		for (char c : t.toCharArray())
			map[c]++;

		for (int i = 0; i < s.length(); i++)
		{
			char c = s.charAt(i);
			if (map[c]-- > 0)
				count--;

			while (count == 0)
			{
				if (i - left + 1 < minLen)
				{
					minLen = i - left + 1;
					start = left;
				}

				if (map[s.charAt(left)]++ == 0)
					count++;
				left++;
			}
		}

		return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start
				+ minLen);

	}

}

嘿嘿

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值