Leetcode队列与⼴度优先搜索题目

以下为Datawhale Leetcode开源学习思路总结,以下代码均为Leetcode代码,但不一定是最优解,仅供参考学习。

622. 设计循环队列

设计循环队列时,代码可复用,循环队列实际上是对固定数组在遍历位置处相对固定长度取模,本代码使用vector,也可使用数组,效率更高。代码如下:

class MyCircularQueue {
public:
    MyCircularQueue(int k) {
        v_.resize(k);
        begin_ = 0;
        end_ = begin_;
        len_ = k;
    }
    
    bool enQueue(int value) {
        if(isFull()) return false;
        v_[(end_++)%len_] = value;
        return true;
    }
    
    bool deQueue() {
        if(isEmpty()) return false;
        begin_++;
        return true;
    }
    
    int Front() {
        if(isEmpty()) return -1;
        return v_[begin_%len_];
    }
    
    int Rear() {
        if(isEmpty()) return -1;
        return v_[(end_-1)%len_];
    }
    
    bool isEmpty() {
        return begin_ == end_;
    }
    
    bool isFull() {
        return (end_)%len_ == begin_%len_ && begin_ != end_;
    }
    vector<int> v_;
    int begin_, end_;
    int len_;
};

346. 数据流中的移动平均值

这道题的难点在于当窗口满了以后,此时向后移动窗口时,要减去最早加入窗口的数,因此需要保存最早入窗口元素的值,本题看似是窗口在滑动,实际上就是一个循环队列,通过取模运算,和begin_end_来确定队列元素。本题不难,直接贴出代码:

class MovingAverage {
public:
    MovingAverage(int size) {
        len_ = size;
        sum_ = 0.0;
        begin_ = end_ = 0;
        v_.resize(len_);
        cnt = 0;
    }
    
    double next(int val) {
        if(cnt < len_) {
            ++cnt;
            sum_ += val;
            v_[(end_++)%len_] = val;
        } else {
            sum_ += (double)val;
            sum_ -= (double)v_[(begin_++)%len_];
            v_[(end_++)%len_] = val;
        }
        return 1.0*sum_ / cnt;
    }

    int len_;
    int cnt;
    double sum_;
    vector<int> v_;
    int begin_, end_;
};

225. ⽤队列实现栈

本题通过队列实现栈,其底层可使用deque封装,也可使用queue封装,deque封装比较简单,这里不做说明;关于queue封装,重点在于push操作,核心代码如下:

void push(int x) {
    q.push(x);
    for (int i=1; i<q.size(); i++) {
        q.push(q.front());
        q.pop();
    }
}

然后我再贴出我使用deque实现的代码:

class MyStack {
public:
    MyStack() {}
    
    void push(int x) {
        q_.push(x);
    }
    
    int pop() {
        int size = q_.size();
        while(--size) {
            q_.push(q_.front());
            q_.pop();
        }
        int res = q_.front();
        q_.pop();
        return res;
    }
    
    int top() {
        return q_.back();
    }
    
    bool empty() {
        return q_.empty();
    }
    queue<int> q_;
};

286. 墙与⻔

贴出题目:
在这里插入图片描述

这道题要计算各个房子距离门的位置,那么我们可以从门出发,通过bfs将门周围一圈,两圈,三圈…一直到地图所有位置的距离计算出来,代码中通过dis+1赋值,每圈遍历结束再给dis++,需要注意的是每遍历一圈的个数需要用固定变量保存起来,而不能使用库函数.size(),因为在遍历途中我们会向队列元素,致使.size()得到的结果发生动态变化,影响遍历,具体代码实现如下:

class Solution {
public:
    void wallsAndGates(vector<vector<int>>& rooms) {
        queue<pair<int, int>> q;
        for(int i = 0; i < rooms.size(); ++i) {
            for(int j = 0; j < rooms[0].size(); ++j) {
                if(rooms[i][j] == 0) {
                    q.push({i, j});
                }
            }
        }
        int dis = 0;
        while(q.size()) {
            int len = q.size();
            for(int i = 0; i < len; ++i) { //bfs遍历周围每一圈
                pair<int, int> tmp = q.front();
                q.pop();

                int x = tmp.first, y = tmp.second;
                if(x-1 >= 0 && rooms[x-1][y] > dis+1) {
                    q.push({x-1, y});
                    rooms[x-1][y] = dis+1;
                }
                if(x+1 < rooms.size() && rooms[x+1][y] > dis+1) {
                    q.push({x+1, y});
                    rooms[x+1][y] = dis+1;
                }
                if(y-1 >= 0 && rooms[x][y-1] > dis+1) {
                    q.push({x, y-1});
                    rooms[x][y-1] = dis+1;
                }
                if(y+1 < rooms[0].size() && rooms[x][y+1] > dis+1) {
                    q.push({x, y+1});
                    rooms[x][y+1] = dis+1;
                }
            }
            dis++;
        }
    }
};

上述代码步骤:

  1. 将所有要出发或者要抵达的坐标保存在队列中
  2. 若队列不为空,遍历队列内容,进行某种操作(本题为对应坐标处距离从零开始不断++)后将访问到的点外层点继续加入队列中
  3. 直到队列为空时停止bfs

752. 打开转盘锁

这道题非常经典,值得学习。

本题初始状态为0000,因为一次只能拧动一个位置,所以可抵达的状态有8种,如1000010000100001这四种分别是数字向上变动(由0变为1),9000090000900009这四种状态分别是数字向下变动。我直接贴出票数最高题解:
在这里插入图片描述

本题代码如下:

class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_set<string> deadendsSet(deadends.begin(), deadends.end());
        unordered_set<string> visited;
        int res = 0;
        if(deadendsSet.find("0000") != deadendsSet.end()) {
            return -1;
        }

        queue<string> wheelQueue;
        wheelQueue.push("0000");
        visited.insert("0000");
        while(!wheelQueue.empty()) {
            int levelsize = wheelQueue.size();
            while(levelsize--) {
                string up, down, currentWheel = wheelQueue.front();
                wheelQueue.pop();
                if(currentWheel == target)
                    return res;

                for(int i = 0; i < 4; ++i) {
                    down = up = currentWheel;
                    char upCh = up[i], downCh = down[i];
                    up[i] = (upCh == '9' ? '0' : upCh + 1);
                    down[i] = (downCh == '0' ? '9' : downCh - 1);

                    if(visited.find(up) == visited.end() && deadendsSet.find(up) == deadendsSet.end()) {
                        wheelQueue.push(up);
                        visited.insert(up);
                    }
                    if(visited.find(down) == visited.end() && deadendsSet.find(down) == deadendsSet.end()) {
                        wheelQueue.push(down);
                        visited.insert(down);
                    }
                }
            }
            res++;
        }
        return -1;
    }
};

279. 完全平⽅数

要找出最少平方数的个数,实际上就是bfs时找出最先满足平方数和为n的层数是多少。我们的思路是将<=n的所有平方数罗列出来加入队列,在这些平方数中取数求和,多次bfs,将首先满足和为n的层数作为返回值。具体代码如下:

class Solution {
public:
    int numSquares(int n) {
        if(n <= 0) return 0;

        vector<int> perfectSquares;
        vector<int> cntPerfectSquares(n);
        for(int i = 1; i*i <= n; ++i) {
            perfectSquares.push_back(i*i);
            cntPerfectSquares[i*i-1] = 1;
        }

        if(perfectSquares.back() == n) return 1;

        queue<int> searchQ;

        for(auto &x : perfectSquares)
            searchQ.push(x);

        int currCntPerfectSquares = 1;
        while(!searchQ.empty()) {
            currCntPerfectSquares++;
            int searchQSize = searchQ.size();
            for(int i = 0; i < searchQSize; ++i) {
                int tmp = searchQ.front();

                for(auto &j : perfectSquares) {
                    if(tmp + j == n)
                        return currCntPerfectSquares;
                    else if((tmp+j<n) && (cntPerfectSquares[tmp+j-1] == 0)) {
                        cntPerfectSquares[tmp+j-1] = currCntPerfectSquares;
                        searchQ.push(tmp+j);
                    } else if(tmp+j>n)
                        break;
                }
                searchQ.pop();
            }
        }
        return 0;
    }
};

542. 01 矩阵

本题首先将所有位置为0的地方距离都设置为0,然后将mat0结点坐标全部加入队列queue中,记录距离dis0。具体代码如下:

class Solution {
public:
    bool isvalid(int i, int j, int m, int n) {
        if(i == m || j == n || i < 0 || j < 0) return false;
        return true;
    }
    vector<vector<int>> dir = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}};
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        queue<pair<int, int>> q;    // 存放的是坐标
        int m = mat.size();
        int n = mat[0].size();
        vector<vector<int>> dis(m, vector<int>(n, -1));
        // 把所有mat中0节点坐标全部加入queue中,记录距离dis为0
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(mat[i][j] == 0) {
                    q.push({i, j});
                    dis[i][j] = 0;
                }
            }
        }

        while(!q.empty()) {
            pair<int, int> curr = q.front();
            q.pop();
            for(auto &x : dir) {
                int a = curr.first + x[0];
                int b = curr.second + x[1];

                if(isvalid(a, b, m, n) && dis[a][b] == -1) {
                    q.push({a, b});
                    dis[a][b] = dis[curr.first][curr.second] + 1;
                }
            }
        }
        return dis;
    }
};

322. 零钱兑换

剑指 Offer 13. 机器⼈的运动范围

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值