Leetcode队列

简介

先进先出

#include <iostream>

int main() {
    // 1. Initialize a queue.
    queue<int> q;
    // 2. Push new element.
    q.push(5);
    q.push(13);
    q.push(8);
    q.push(6);
    // 3. Check if queue is empty.
    if (q.empty()) {
        cout << "Queue is empty!" << endl;
        return 0;
    }
    // 4. Pop an element.
    q.pop();
    // 5. Get the first element.
    cout << "The first element is: " << q.front() << endl;
    // 6. Get the last element.
    cout << "The last element is: " << q.back() << endl;
    // 7. Get the size of the queue.
    cout << "The size is: " << q.size() << endl;
}

含有两个元素的队列

定义  queue<pair<int,int>> neighborhoods
入队 neighborhoods.push({i,j})
出队 neighborhoods.pop()
取队首  auto rc=neighborhoods.front();
       int r=rc.first,c=rc.second;
是否为空  neighborhoods.empty()

队列与广度优先算法

和树的层次遍历类似,每次pop出一个节点进行处理,判断是否为目标值。不是的话,遍历其子节点,插入到队列,然后再从队列pop出一个值进行处理,以此循环。

模板
/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    Queue<Node> queue;  // store all nodes which are waiting to be processed
    int step = 0;       // number of steps neeeded from root to current node
    // initialize
    add root to queue;
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        int size = queue.size();   #这个一定要先算出来,不可以在for循环那一行求,因为for循环里面有pop操作,造成size会变化。
        #这个循环可以加,也可以不加,加上的话,类似树的层次遍历,可以统计一共遍历了多少层,在计算一些最小步问题是,需要记录step
        #不加的话,每次pop出单个元素,也可正常运行。
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                add next to queue;
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

例题

1.岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1
示例 2:

输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

//思路:首先遍历查找到“1”的位置,岛屿数目加1(因为只要有"1"在,肯定会有岛屿)然后利用广度优先算法,查找到与其相邻的“1”,并将其置为“0’,直到再也没有"1",结束。
class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int num=0;
        int row=grid.size();
        int column=grid[0].size();
        queue<pair<int,int>> neighborhoods;
        for(int i=0;i<row;i++){
            for(int j=0;j<column;j++){
                if(grid[i][j]=='1'){
                    num++;
                    // 广度优先算法
                    neighborhoods.push({i,j});
                    while(!neighborhoods.empty()){
                       for(int k=0;k<neighborhoods.size();k++){
                       	//处理当前节点
                           auto rc=neighborhoods.front();
                            int r=rc.first,c=rc.second;
                            	//如果为"1',入队,并置为”0“
                            if(r-1>=0 && grid[r-1][c]=='1'){
                                neighborhoods.push({r-1,c});
                                grid[r-1][c]='0';
                            }
                            if(r+1<row && grid[r+1][c]=='1'){
                                neighborhoods.push({r+1,c});
                                grid[r+1][c]='0';
                            }
                            if(c-1>=0 && grid[r][c-1]=='1'){
                                neighborhoods.push({r,c-1});
                                grid[r][c-1]='0';
                            }
                            if(c+1<column && grid[r][c+1]=='1'){
                                neighborhoods.push({r,c+1});
                                grid[r][c+1]='0';
                            }
                            //当前节点出队,并置为0
                            grid[r][c]='0';
                            neighborhoods.pop();
                       }
                        
                    }
                }
            }
        }
        return num;
    }
};

2.完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

//思路:对于每一步,我们都可以减去若干个平方数,剩余的若干和入队,然后再以此出队,知道剩余和为0为止。
//有个小tip,加个记忆序列,可大幅减少计算量,减少重复运算,即如果元素入队前,先判断其是否已经如果队,如果已经入队过,不让其入队,防止重复运算
class Solution {
public:
    int numSquares(int n) {
        queue<int> q;
        //记忆序列,用于记录是否已经入队过
        vector<bool> visited(n+1, false);
        q.push(n);
        int step=0;
        while(!q.empty()){
            int size=q.size();
            for(int i=0;i<size;i++){
                int cur=q.front();
                if(cur==0) return step;
                // vector<int> sum=get_data(cur);
                for(int k=1;k<=sqrt(cur);k++){
                    if(visited[cur-k*k]==false){
                        q.push(cur-k*k);
                        visited[cur-k*k]=true;
                    }
                }
                q.pop();
            }
            step++;
        }
        return step;
    }
};

3.打开转盘锁

你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,‘0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。

锁的初始数字为 ‘0000’ ,一个代表四个拨轮的数字的字符串。

列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。

字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。

示例 1:

输入:deadends = [“0201”,“0101”,“0102”,“1212”,“2002”], target = “0202”
输出:6
解释:
可能的移动序列为 “0000” -> “1000” -> “1100” -> “1200” -> “1201” -> “1202” -> “0202”。
注意 “0000” -> “0001” -> “0002” -> “0102” -> “0202” 这样的序列是不能解锁的,
因为当拨动到 “0102” 时这个锁就会被锁定。

//思路:对于每个状态,接下来的可能状态有8个,所以,处理当前元素时,先判断是否为目标值,不是的话,将其出队,然后将其下一个状态可能值入队,并用step记录是第几次。
//tip:加个记忆序列,防止重复运算
class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        int step=0;
        queue<string> q;
        //记忆序列,记录是否出现过
        unordered_set<string> seen = {"0000"};
        unordered_set<string> dead(deadends.begin(), deadends.end());
        q.push("0000");
        if(dead.count("0000")) return -1;
        while(!q.empty()){
            int size=q.size();
            for(int k=0;k<size;k++){
                string cur=q.front();
                // status.push_back(cur);
                if(cur.compare(target)==0) return step;
                q.pop();
                vector<string> next=get_str(cur);
                for(int i=0;i<next.size();i++){
                    if(!dead.count(next[i])){
                        if(!seen.count(next[i])){
                            q.push(next[i]);
                            seen.insert(move(next[i]));
                        }
                        // q.push(next[i]);
                    }
                }
            }
            step++;
            // if(step>3){
            //     return step;
            // } 
        }
        return -1;
    }
    //查找接下来的8个可能状态
    vector <string> get_str(string cur){
        vector<string> result;
        int step=0;
        while(step<4){
            string s1(cur);
            string s2(cur);
            if(s1[step]=='9'){
                s1[step]='0';
            }else{
                s1[step]=char(s1[step]+1);
            };
            if(s2[step]=='0'){
                s2[step]='9';
            }else{
                s2[step]=char(s2[step]-1);
            };
            result.push_back(s1);
            result.push_back(s2);
            step=step+1;
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值