LeetCode题解之队列(一)

155 阅读3分钟

1.队列基础知识

先进先出,题目中用到的主要是头尾操作,栈是只操作栈顶

2.基本题目

3. 无重复字符的最长子串(剑指 Offer 48. 最长不含重复字符的子字符串)

#include <typeinfo>
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //要求是连续的子串!=序列
        unordered_map<char,int> hash;
        queue<char> q;
        int res = 0;
        for(auto c:s)//一边入队,一边看新加入的元素是否导致重复,重复了就出队
        {
            hash[c] ++;
            q.push(c);
            while(hash[c] > 1) hash[q.front()] --, q.pop();
            res = max(res, (int)q.size());//q.size()不能直接比较,要转化成int,本身是unsinged int
        }
        return res;
    }
};

剑指 Offer 59 - II. 队列的最大值

class MaxQueue {
public:
    queue<int> q;
    deque<int> max_q;
    MaxQueue() {

    }
    
    int max_value() {
        if(max_q.empty()) return -1;
        else return max_q.front();
    }
    //维护一个单调递减的双端队列,最大值直接取头即可
    //当一个元素进入队列的时候,它前面所有比它小的元素就不会再对答案产生影响!所以遇到大的替换,遇到小的加入
    void push_back(int value) {
        q.push(value);
        while(!max_q.empty() && value > max_q.back()) max_q.pop_back();//维护一个单调递减的数组
        max_q.push_back(value);
    }
    
    int pop_front() {
        if(q.empty()) return -1;
        else
        {
            int t = q.front();
            q.pop();
            if(max_q.front() == t) max_q.pop_front();//看影响当前最大值不即可
            return t;
        }
        
    }
};

剑指 Offer 59 - I. 滑动窗口的最大值(239. 滑动窗口最大值)

//第二次做,稍微有点区别,更好理解
class Solution {
public:
   vector<int> maxSlidingWindow(vector<int>& nums, int k) {
       int n = nums.size();
       if(k == 1) return nums;//如果k==1那么提前把第一个数加入队列后,会无法融入到答案中,所以建议用下面一种方法一起做!
       //用一个队列存最大值的下标,维护一个递减的序列,这样如果队列头的下标在窗口内,那就一直是最大值
       //需要用双端序列
       deque<int> q;
       vector<int> res;
       q.push_back(0);
       for(int i = 1; i < n; i ++)//i-j+1=k则j=i+1-k
       {
           int j = i + 1 - k;
           if(q.front() < j) q.pop_front();//窗口滑过了目前队列头存的最大值,则队列弹出一个
           while(!q.empty() && nums[i] > nums[q.back()]) q.pop_back(); //如果新数是最大的,那为空了之后就报错了,所以需要判断下是否为空,为空就不继续弹了
           q.push_back(i);
           if(j >= 0) res.push_back(nums[q.front()]);
       }
       return res;
   }
};
//第一次做的

class Solution {
public:
   vector<int> maxSlidingWindow(vector<int>& nums, int k) {
       //求大数:递减序列:这个大数一直在, 则肯定是他,有小数则加入,因为当大数弹出,它有可能是剩下的大数;有更大的数则把比它小的逆序的弹出
       //求小数:递增序列:因为这个小数一直在则肯定是最小,有大数加入可能是接下来的最小,有小数加入需要把逆序的弹出
       deque<int> q;
       vector<int> res;
       for(int i = 0; i < nums.size(); i ++)
       {
           int j = i - k + 1;
           if(!q.empty() && j > q.front()) q.pop_front();//队头:超过时需要弹出队头,第一个数就不会被弹出了
           while(!q.empty() && nums[i] >= nums[q.back()]) q.pop_back();//队尾:加入的数更大,为了构造递减序列,所以往前一直弹出末尾,插入新数坐标
           q.push_back(i);//上面的头尾都是非空的,即空的直接加入,数更小时也直接加入
           if(j >= 0) res.push_back(nums[q.front()]);
       }
       return res;
   }
};

127. 单词接龙

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        // 将vector转成unordered_set,提高查询速度
        unordered_set<string> wordSet(wordList.begin(), wordList.end());
        // 如果endWord没有在wordSet出现,直接返回0
        if (wordSet.find(endWord) == wordSet.end()) return 0;
        // 记录word是否访问过
        unordered_map<string, int> visitMap; // <word, 查询到这个word路径长度>
        // 初始化队列
        queue<string> que;
        que.push(beginWord);
        // 初始化visitMap
        visitMap.insert(pair<string, int>(beginWord, 1));

        while(!que.empty()) {
            string word = que.front();
            que.pop();
            int path = visitMap[word]; // 这个word的路径长度
            for (int i = 0; i < word.size(); i++) {
                string newWord = word; // 用一个新单词替换word,因为每次置换一个字母
                for (int j = 0 ; j < 26; j++) {
                    newWord[i] = j + 'a';
                    if (newWord == endWord) return path + 1; // 找到了end,返回path+1
                    // wordSet出现了newWord,并且newWord没有被访问过
                    if (wordSet.find(newWord) != wordSet.end()
                            && visitMap.find(newWord) == visitMap.end()) {
                        // 添加访问信息
                        visitMap.insert(pair<string, int>(newWord, path + 1));
                        que.push(newWord);
                    }
                }
            }
        }
        return 0;
    }
};

438. 找到字符串中所有字母异位词

class Solution {
public:
   vector<int> findAnagrams(string s, string p) {
       vector<int>ans;
       if(p.size()>s.size()||s.size()==0) return ans;
       vector<int>need(128);
       vector<int>windows(128);
       for(char a:p) need[a]++;
       for(int i=0;i<p.size()-1;i++) windows[s[i]]++;
       int l=0,r=p.size()-1;//窗口是[l,r]
       while(r<s.size())
       {
           cout<<l<<r<<endl;
           for(auto x: windows) cout<<x;
           cout<<endl;
           windows[s[r++]]++;
           if(windows==need) ans.push_back(l);
           windows[s[l++]]--;

       }
       return ans;
   }
};