leetcode第一刷_Minimum Window Substring

好题,字符串,线性时间。

我觉得第一次拿到这个题的人应该不会知道该怎么做吧,要么就是我太弱了。。先搞清楚这个题要求的是什么。从一个长字符串中找一个字串,这个字串中的字符完全包含了另一个给定目标串中的字符,且这个字串的长度要求最小。还有一个非常重要的简化,题干指明了要求这种最短字串只有一个,这个限制其实暗示了这道题的整体思路,只要找到一个长串,然后缩减到不能缩减即可。

从题目的要求出发可以发现,这道题对于字符串中字符的顺序是没有要求的,因此可以很自然的想到用hash表来保存目标串中的每个字符的个数,然后在源字符串中找到一个字串,包含的字符个数大于等于目标串中的即可。难就难在怎么实现这个功能。

可以把目标串中每个字符的个数作为它的需求,每当在长字符串中找到了一个字符,这个字符在目标串中存在,那么需求应该减少1,当需求等于0的时候,表示到目前为止,长字符串中的字符可以恰好满足目标串中这个字符的需求了,如果一个目标串字符的需求变成了负值,说明在当前长度下,在长字符串中对这个字符的供应过剩了。为了描述简便,我定义当长字符串在目标串对这个字符的需求为正时提供了这个字符,为满足了刚性需求,否者是供应过剩。接下来还有一个问题,怎样知道目标串被完全满足了呢?你当然可以去逐个的扫描需求是不是都变成非正的了,但是还有一个更加简单的方法,那就是把目标串的长度看做是总需求,当满足刚性需求时,总需求减1,当总需求变成0时,说明目标串被满足了。

上面描述的过程在长字符串中找到了一个字串,可以完全满足目标串,但并不保证是最短的,因为很多字符在其他字符没得到满足时已经供应过剩了,怎样把这部分多余的去掉呢?从起点开始往后扫秒长字符串,如果当前字符根本不存在于目标串中,可以直接pass,如果存在于目标串中,且供应过剩了,那么这个字符可以从我们的字串中去掉,相当于我们的字串缩短了,但是要记得把需求量++,因为供应量减少了。知道一个字符,它既存在于目标串中,且他的需求量正好是等于0的,我们就得停下了,因为这时候的全部是刚性需求,不能再减少供应了。

代码如下,并没有最优化,不过思路是写出来了。

class Solution {
public:
    string minWindow(string S, string T) {
        int ct1[270], ct2[270];
        int mlen1 = S.length();
        int mlen2 = T.length();
        memset(ct1, 0, sizeof(ct1));
        memset(ct2, 0, sizeof(ct2));
        int hole = mlen2, minSize = INT_MAX, start = 0, minstart;
        for(int i=0;i<mlen2;i++){
            ct1[T[i]]++;
            ct2[T[i]]++;
        }
        for(int i=0;i<mlen1;i++){
            if(ct2[S[i]]>0){
                ct1[S[i]]--;
                if(ct1[S[i]]>=0)
                    hole--;
            }
            if(hole == 0){
                while(start<mlen1){
                    if(ct2[S[start]]>0){
                        if(ct1[S[start]]<0)
                            ct1[S[start]]++;
                        else
                            break;
                    }
                    start++;
                }
                if(minSize>i-start+1){
                    minSize = i-start+1;
                    minstart = start;
                }
            }
        }
        if(minSize == INT_MAX)
            return "";
        return S.substr(minstart, minSize);
    }
};

leetcode第一刷_Minimum Window Substring,布布扣,bubuko.com

时间: 2024-10-13 02:11:48

leetcode第一刷_Minimum Window Substring的相关文章

leetcode第一刷_Minimum Path Sum

可以用递归简洁的写出,但是会超时. dp嘛.这个问题需要从后往前算,最右下角的小规模是已知的,边界也很明显,是最后一行和最后一列,行走方向的限制决定了这些位置的走法是唯一的,可以先算出来.然后不断的往前推算. 用distance[i][j]保存从当前位置走到最右下角所需的最短距离,状态转移方程是从distance[i+1][j]和distance[i][j+1]中选一个小的,然后再加上自身的. 代码很容易理解,这就是dp的魅力.空间上是可以优化的,因为当前状态只与后一行和后一列有关系. clas

leetcode第一刷_Minimum Depth of Binary Tree

非常easy的题目.只是还是认为要说一下. 最小深度.非常快想到bfs,层序遍历嘛.本科的时候实在是没写过多少代码,一開始竟然想不到怎么保存一层的信息.后来想到能够压入一个特殊的对象,每次到达这个对象就知道是一层了.我用的是空指针.认为这个适用性还是不错的.一层的节点入队结束后,应该压入一个NULL.当一层的节点都处理完.遇到NULL的时候,要在队列尾部再入队一个NULL,这是后一层的分界线嘛. 昨天在还有一道题上看到了还有一种做法.用一个数据结构vector<set<*> >(2

leetcode第一刷_Binary Tree Inorder Traversal

递归实现当然太简单,也用不着为了ac走这样的捷径吧..非递归实现还挺有意思的. 树的非递归遍历一定要借助栈,相当于把原来编译器做的事情显式的写出来.对于中序遍历,先要訪问最左下的节点,一定是进入循环后,不断的往左下走,走到不能走为止,这时候,能够从栈中弹出訪问的节点,相当于"左根右"过程的"根",然后应该怎么做呢?想一下中序遍历完根节点之后应该干嘛,对,是走到右子树中继续反复这个过程,可是有一点,假设这个节点不包括右子树怎么办?这样的情况下,下一个应该訪问的节点应该

leetcode第一刷_Sqrt(x)

这道题乍看下来非常简单,实际上要注意的问题非常多. 注意看给出来的函数的接口,返回的是int值,也就是计算结果是个近似值.怎样求呢?难道是从2开始往上算?直到某个值正好接近x?当然不行,肯定超时了.再仔细想一下,对了,有二分法,从最大的开始,每次计算一下平方,如果结果比x大,那么缩短上界,否则提高下界. 思想很正确,下面的问题是最大的那个值是多少?你会毫不犹豫的说出是x啊,x的平方根肯定比x小吧.好,那如果x是INT_MAX呢,你想用什么类型来存储这个平方的结果?而且这样每次减半,也得好一会儿才

leetcode第一刷_Subsets II

要求子集,有非常现成的方法.N个数,子集的个数是2^N,每个元素都有在集合中和不在集合中两种状态,这些状态用[0,pow(2,N)]中每个数来穷举,如果这个数中的第i位为1,说明当前集合中包含源数组中的第i个数. 至于有没有重复的元素,大部分有重复元素的问题,都可以借助一个vis集合,里面存放所有已经求得的集合或者其他形式的解,只有少数题目会超时,哪些问题具体的说. class Solution { public: vector<vector<int> > subsetsWithD

leetcode第一刷_Decode Ways

这道题还挺难的.递归的思路是好想,不过不出意料的超时了. dp嘛.想一下i-1的编码加上第i个编码会怎样,如果加上的这个编码不是0,那么这一位可以独立解码,那长为i的解码个数至少是长为i-1的解码个数.还有呢?如果i-1位是1,可以把i-1位和i位同时解码出来,还有呢?如果i-1位是2而i位是0-6中的数字,也可以同时解码这两位编码.满足这个条件的时候,当前长度的解码个数还要加上i-2时的解码个数. 完全可以用一个数组存放过去的结果,但是很明显,当前的结论只与前一个和前前一个结果有关系.只要用三

leetcode第一刷_Gray Code

说到格雷码,应该没人不知道,具体它有什么用,我还真不是很清楚,我室友应该是专家.生成的规律不是很明显,之前看到帖子讲的,这会儿找找不到了.. 思想是这样的,如果有n位,在第2^(n-1)个编码下面画一条水平线的话,你会发现除了第一位之外,其他位都是关于这条线对称的,如下,以三位格雷码举例: 000 001 011 010 --------------------- 110 111 101 100 很神奇吧,我以前是不知道这个规律的.从一开始的一位格雷码,0,1,开始,每次对称的在上一个前面添加上

leetcode第一刷_Permutation Sequence

这道题还挺好的,如果你的思路是每次生成一个全排列,然后累计到k次,那么停下来吧,肯定超时了亲.. 微软今年的笔试题里有一道类似的,我之前已经提到过了,是只有0和1的字符串,求第k个排列是什么样子的.这道题比那个要难一些,但是总体的思路是一样的.假设有n个数要组成排列,求第k个排列.像填表一样,从高位往地位,逐个填写.先考虑有n-1个数要组成排列,最多有(n-1)!种情况,当第n个数加入后,第n个数可以是从1增加到n的,没增加1,所包含的全排列数就会增加(n-1)!,因此,如果用k/(n-1)!,

leetcode第一刷_Spiral Matrix

我觉得这个题好无聊啊,好端端一个数组,干嘛要跟比巴卜一样转一圈输出呢.. 思想很简单,每次从左到右,再从上到下,在从右到左,再从下到上.问题是每次到什么时候该改变方向.我的做法是用一个变量保存当前在第几层,这个层是相对于从外向内有几圈来说的.注意想清楚边界的话这个题一点也不难.有个细节,我的循环退出条件是访问的数跟矩阵总个数之间的关系,如果有一次在判断进入循环是条件是满足的,但是在循环内部不满足了,我的策略是忽略这种情况,虽然这样会在结果集中多加一些重复的数据,但是以我的算法,一定是先访问没有访