leetcode -- 队列总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/llz62378/article/details/78324379

队列大部分应用都是与其他数据结构和算法结合,leetcode中队列的题目也比较少,免费题目只有621. Task Scheduler和363.Max Sum of RectangleNo Larger Than K,363后面再解决。

与其他数据结构和算法结合:

(1)   拓扑排序,判断有向无环图中是否有环。用队列保存入度为0的元素,用一个一维数组indegree存放每个节点的入度,并每取出一个元素,就对indegree进行更新。

(2)   广度优先搜索,无向图寻找最短路径,求最短路径长度,条数。

(3)   树的层次遍历

621. Task Scheduler

此题给出一个任务序列,n是相同的任务至少需要的间隔数量。如果相同任务的间隔不能满足至少n个,那么就要向其中插入idle. 所以需要我们设计任务序列使之在尽可能少的时间完成这些任务,尽可能减少或不插入idle。本题solution中有三种解决方案,其中第二种运用队列。下面将具体介绍这三种方法:

(1)    贪心法

思路:为了确保尽可能少的idle,且task从A到Z做多有26种任务,只有将数量较多且相同任务的间隔尽可能到达最小间隔时(贪心),才能使idle更少。例如,任务有A, B, C, D, E,他们的数量分别为6, 1,1, 1, 1n = 2. 如果采用A, B, C, D, E作为第一次循环,那么还剩下5A,而这5A就需要更多的idle放在其中了,A, B, C, D, EA, idle,idle,A,idle,idle, A,idle,idle,A,idle,idle, A,总共用时18。但如果遵循每次将尽可能多数量的task先运行,且间隔到达最小允许的间隔,那么就可以使数量最多的task尽可能的和数量第二多,数量第三多task进行组合,减少数量较多的task剩下的可能,从而缩短总时间了。例如这里A6个是最多的元素,就要减少就剩下A的可能,因为剩下的A越多,最后剩下的A之间就要只能选择间隔nidle了,没有其他选择了。所以A要尽可能的和其他元素进行组合。所以A,B,C,A,D,E,A,idle,idle, A, idle,idle,A, idle,idle,A,总共用时16,减少了两个idle

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        vector<int> task(26); // size = 26
        for(int i = 0; i < tasks.size(); ++i)
        {
            task[tasks[i] - 'A']++;
        }
        
        int timer = 0;
        sort(task.begin(), task.end());
        while(task[25] > 0)
        {
            int i = 0;
            while(i <= n)
            {
                if(task[25] == 0)
                    break;
                
                if(i < 26 && task[25 - i] > 0)
                    task[25 - i]--;
                
                ++i;
                ++timer;
            }
            
            sort(task.begin(), task.end());
        }
        
        return timer;
    }
};

(2)   优先队列

思路:和第一种方法的大体思路是一致的,采用优先队列的好处是在插入元素时自动排序。省去了用数组每次要重新排序的过程。

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        vector<int> task(26); // size = 26
        for(int i = 0; i < tasks.size(); ++i)
        {
            task[tasks[i] - 'A']++;
        }
        
        priority_queue<int> q; // 默认大根堆,且自动排序
        for(int i = 0; i < task.size(); ++i)
        {
            if(task[i] > 0)
                q.push(task[i]);
        }
        cout << q.size() << endl;
        
        int timer = 0;
        vector<int> tmp; // 缓存每次执行的任务,他们所剩下的任务数量
        while(!q.empty())
        {
            
            int i = 0;
            while(i <= n)
            {
                if(q.empty() && tmp.size() == 0)
                    break;
                
                if(!q.empty())
                {
                    if(q.top() > 1)
                        tmp.push_back(q.top() - 1);
                    q.pop();
                }
                
                ++timer;
                ++i;
            }
            
            for(int j = 0; j < tmp.size(); ++j)
            {
                q.push(tmp[j]);
            }
            tmp.clear();
        }
        return timer;
    }
};

(3)    直接计算

思路:先计算idle的数量,再加上tasks中任务数量就是总的时间。除了最大出现的task外其他位置全部被填充为idle, 之后再减去所有的任务,剩下的就是所有的idle。


class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
        vector<int> task(26); // size = 26
        for(int i = 0; i < tasks.size(); ++i)
        {
            task[tasks[i] - 'A']++;
        }
        sort(task.begin(), task.end());
        
        int maxTask = task[25] - 1;    // tasks中任务出现的最大次数
        int idleCnt = maxTask * n;     // 全部填充idle的时间
        for(int i = 24; i >=0 && task[i] > 0; --i)
        {
            idleCnt -= min(task[i], maxTask);
        }
        return idleCnt > 0? idleCnt + tasks.size() : tasks.size();
    }
};


猜你喜欢

转载自blog.csdn.net/llz62378/article/details/78324379
今日推荐