• LeetCode 76. 最小覆盖子串


    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    LeetCode 76. 最小覆盖子串

    题目

    给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

    示例:

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

    说明:

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

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/minimum-window-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    很自然能想到的是用滑动窗口来解决;
    题目有个坑就是,对于s="aaa"和t="aa",答案是"aa"而不是"a",就是说,子串必须包含t的所有字母数量至少是t的长度;

    思路1-滑动窗口

    因为本题参数都是字母,故可以转为数组来处理;
    步骤:

    1. 创建t对应的数组need并统计其字母数量为窗口参照,创建用来搜索s的窗口数组search,窗口双指针left和right从s的0位置开始,记录匹配到t中字母的计数器count和最小覆盖子串的下标记录数组min;
    2. right开始遍历s,统计到search,且若字母在need存在,则count++且最多统计need中的上限值;
    3. 当count等于t的长度时表明找到了一个覆盖子串,此时停止right,从left开始缩小窗口,若找到了更小的坐标则更新min;

    算法复杂度: n1为s的长度,n2为t的长度

    • 时间复杂度: $ {color{Magenta}{Omicronleft(n1+n2 ight)}} $
    • 空间复杂度: $ {color{Magenta}{Omicronleft(1 ight)}} $

    算法源码示例

    package leetcode;
    
    import java.util.HashMap;
    
    /**
     * @author ZhouJie
     * @date 2020年3月6日 下午9:41:21 
     * @Description: 76. 最小覆盖子串
     *
     */
    public class LeetCode_0076 { 
    
    }
    class Solution_0076 {
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月6日 下午11:46:51 
    	 * @param: @param s
    	 * @param: @param t
    	 * @param: @return
    	 * @return: String
    	 * @Description: 2-按照题意要求,将1的改造一下,hash哈希表存对应字符出现次数;
    	 * 				cache改为map类型,思路不变,但是改为校验cache的map与has是否完全一致即可;
    	 * 				
    	 * 				因为题目中的都是字母,所以不用HashMap改用128长度的数组足矣,
    	 *
    	 */
    	public String minWindow_2(String s, String t) {
    		int tLen = 0, sLen = 0;
    		// 特例判断
    		if (t == null || (tLen = t.length()) == 0) {
    			return "";
    		}
    		// 特例判断
    		if (s == null || (sLen = s.length()) < tLen) {
    			return "";
    		}
    		// 需要找到的字母和数量,转为数组记录
    		int[] need = new int[128];
    		for (char c : t.toCharArray()) {
    			need[c]++;
    		}
    		// 滑动窗口中的字母和数量
    		int[] search = new int[128];
    		// 滑动窗口左右指针和统计匹配到t中字母的计数count
    		int left = 0, right = 0, count = 0;
    		int[] min = new int[] { 0, sLen };
    		while (right < sLen) {
    			char c = s.charAt(right);
    			// 记录s中当前字母数量,若是need中要找的,则count++且最多加need中的上限个
    			search[c]++;
    			if (need[c] > 0 && need[c] >= search[c]) {
    				count++;
    			}
    			// 若s中的字母在t中全找到了,则开始从左侧缩小窗口
    			while (count == tLen) {
    				c = s.charAt(left);
    				if (need[c] > 0 && need[c] >= search[c]) {
    					count--;
    				}
    				// 若找到了更小的窗口则更新
    				if (right - left < min[1] - min[0]) {
    					min[0] = left;
    					min[1] = right;
    				}
    				search[c]--;
    				left++;
    			}
    			right++;
    		}
    		// 需要验证min[1],未找到时返回"",否则截取s返回,记得截取右侧位置要+1
    		return min[1] == sLen ? "" : s.substring(min[0], min[1] + 1);
    	}
    }
    
    
  • 相关阅读:
    js 正则表达式 test match exec三个方法的异同
    网页使用MD5加密
    解决Google地图和字体api无法加载的问题(转)
    Javascript 的addEventListener()及attachEvent()区别分析
    get与post的区别
    清除浮动的几种方法
    zoom属性(IE私有属性)
    class,id和name的区别
    深夜偷精之反射函数
    jQuery和js区别
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12781194.html
Copyright © 2020-2023  润新知