Leetcode有關滑動窗口的題目

代碼是用C寫的。
239. 滑動窗口最大值
使用單調雙端隊列記錄窗口內可能的最大值。
遍歷數組一次,由於是找窗口內的最大值,在窗口移動的過程中,需要把窗口內可能成爲接下來窗口最大值的數字先記錄在隊列中。
入窗口:每次有一個數字滑入窗口的時候,這個數字必定需要記錄在窗口內,因爲以這個數字爲起始位置的窗口是未知的,因此這個數字可能成爲窗口的最大值,當這個數字進入窗口後,我們需要對隊列裏候選的最大值進行判斷,如果發現先進隊列的數字比當前數字要小,那麼在當前數字成爲窗口內最大值候選的時候,比它小的數字就不可能成爲最大值,因此需要把這些數字彈出隊列。
每次進入隊列都進行上述判斷,因此隊列中的數字一定是按照從大到小的順序排列。由於隊列中的數字必定是在窗口內的,那麼此時窗口內的最大值就是隊列頭部的數字。
出窗口:當一個數字進入窗口,必定有另一個數字從窗口劃出,因此需要判斷出窗口的數字是否爲隊列的頭部,如果是,那麼從隊列中刪除,因此這個數字已經不在窗口內了,那麼必定不會成爲窗口最大值的候選。
例如:nums = [1,3,-1,-3,5,3,6,7], 和 k = 3

/**
 * 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章