Leetcode有关滑动窗口的题目

代码是用C写的。
239. 滑动窗口最大值
使用单调双端队列记录窗口内可能的最大值。
遍历数组一次,由于是找窗口内的最大值,在窗口移动的过程中,需要把窗口内可能成为接下来窗口最大值的数字先记录在队列中。
入窗口:每次有一个数字滑入窗口的时候,这个数字必定需要记录在窗口内,因为以这个数字为起始位置的窗口是未知的,因此这个数字可能成为窗口的最大值,当这个数字进入窗口后,我们需要对队列里候选的最大值进行判断,如果发现先进队列的数字比当前数字要小,那么在当前数字成为窗口内最大值候选的时候,比它小的数字就不可能成为最大值,因此需要把这些数字弹出队列。
每次进入队列都进行上述判断,因此队列中的数字一定是按照从大到小的顺序排列。由于队列中的数字必定是在窗口内的,那么此时窗口内的最大值就是队列头部的数字。
出窗口:当一个数字进入窗口,必定有另一个数字从窗口划出,因此需要判断出窗口的数字是否为队列的头部,如果是,那么从队列中删除,因此这个数字已经不在窗口内了,那么必定不会成为窗口最大值的候选。
例如:nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
Leetcode有关滑动窗口的题目_第1张图片Leetcode有关滑动窗口的题目_第2张图片Leetcode有关滑动窗口的题目_第3张图片Leetcode有关滑动窗口的题目_第4张图片Leetcode有关滑动窗口的题目_第5张图片Leetcode有关滑动窗口的题目_第6张图片

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize){
    int start=0,end=0,i;
    int queue[numsSize+1];
    int* rst=(int*)malloc(sizeof(int)*(numsSize+1));
    if(k>numsSize)return NULL;
    *returnSize=0;
    for(i=0;i<numsSize;i++){
        if(i>=k){
            if(queue[start]==nums[i-k])start++;
        }
        while((end-start)>0){//队列中有比当前放入的数字大的数,删掉
            if(nums[i]>queue[end-1]){
                end--;
            }
            else
            break;
        }
        queue[end++]=nums[i];
        if(i>=k-1){
            rst[*returnSize]=queue[start];
            (*returnSize)++;
        }
    }
    return rst;
}

567. 字符串的排列
这一题窗口大小不确定,每次窗口右端不断扩大的时候判断是否满足了题目要求,如果还没有满足,判断当前字符加入后,当前字符的数量在窗口内多了还是少了 ,如果少了,那么继续增大窗口右端;如果多了,那么需要从窗口左端缩小,依次遍历直到除去一个相同的字符。

bool checkInclusion(char * s1, char * s2){
    int i,j,len1,len2,start=0;
    len1=strlen(s1);len2=strlen(s2);
    if(len1==0)return true;
    if(len2==0)return false;
    int letter[30],pat[30];
    memset(letter,0,sizeof(letter));
    memset(pat,0,sizeof(pat));
    for(i=0;i<len1;i++){
        letter[s1[i]-'a']++;
    }
    for(i=0;i<len2;i++){
        pat[s2[i]-'a']++;
        for(j=0;j<26;j++){//判断当前子串是否符合要求
            if(letter[j]==pat[j])continue;
            else
            break;
        }
        if(j==26)return true;
        if(letter[s2[i]-'a']==0){//子串s2没有当前字符。那么子串重新开始选取
            memset(pat,0,sizeof(pat));start=i+1;//start标记窗口的左侧
        }
        else if(letter[s2[i]-'a']>=pat[s2[i]-'a']){//进入窗口,如果所选子串中当前字符还不够,那么直接加入即可
            continue;
        }
        else{//出窗口,所选子串中当前字符出现的次数多了一次,需要在前面的串中去掉和当前字符一样的数字
            for(j=start;j<=i;j++){
                pat[s2[j]-'a']--;start++;
                if(s2[j]==s2[i])break;
            }
        }
    }  
    return false;
}

76. 最小覆盖子串
这一题和上一题类似,但是这一题只要保证串中有匹配串的所有字符即可,可以有其他的字符存在,题目要求最短满足要求的串。思路和上面一题类似。

char * minWindow(char * s, char * t){
    int i,j,len1,len2;
    len1=strlen(s);
    len2=strlen(t);
    if(len2==0)return t;
    if(len1==0)return "";
    int letter[256],pat[256];
    char* rstc=(char*)malloc(sizeof(char)*(len1+1));
    memset(letter,0,sizeof(letter));
    memset(pat,0,sizeof(pat));

    for(i=0;i<len2;i++){
        pat[t[i]]++;
    }
    for(i=0;i<len1;i++){//填充窗口,使得窗口内包含S2中的所有字符
        letter[s[i]]++;
        for(j=0;j<256;j++){
            if(pat[j]<=letter[j])continue;
            else
            break;
        }
        if(j==256)break;
    }
    if(i==len1)return "";
    int rst=len1;
    int start=0,rstart=0,end=i;
    for(j=start;j<=i;j++){
        if(pat[s[j]]==0)start++;
        else if(pat[s[j]]<letter[s[j]]){
            letter[s[j]]--;start++;
        }
        else break;
    }
    if(rst>i-start+1){rst=i-start+1;rstart=start;end=i;}
    i++;
    for(i;i<len1;i++){
        letter[s[i]]++;
        if(s[i]==s[start]){
            start++;    
            letter[s[i]]--;
            for(j=start;j<=i;j++){
                if(pat[s[j]]==0)start++;
                else if(pat[s[j]]<letter[s[j]]){
                    letter[s[j]]--;start++;
                }
                else break;
            }
            if(rst>i-start+1){rst=i-start+1;rstart=start;end=i; }    
        }
    }
    for(j=rstart;j<=end;j++){
        rstc[j-rstart]=s[j];
    }
    rstc[end-rstart+1]='\0';
    return rstc;
}

你可能感兴趣的:(滑动窗口,leetcode)