Leetcode C++ 队列
Leetecode 102
102. Binary Tree Level Order Traversal
Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level).
- 思路:
二叉树的宽度优先遍历(BFS问题)。有两种思路,递归和迭代。-
递归:
-
迭代(queue):
通过使用queue对象记录每层的节点,再弹出queue时,通过首先计算queue对象中的size数,保证在一个循环中只弹出一层的节点,同时压入每个弹出节点的左右子孩子节点。
vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int> > res; if (!root) return res; queue<TreeNode*> que; que.push(root); while (!que.empty()) { int size = que.size(); vector<int> level; for (int i = 0; i < size; ++i) { TreeNode* node = que.front(); que.pop(); level.push_back(node->val); if (node->left) que.push(node->left); if (node->right) que.push(node->right); } res.push_back(level); } return res; }
-
Leetecode 107
107. Binary Tree Level Order Traversal II
Given a binary tree, return the bottom-up level order traversal of its nodes’ values. (ie, from left to right, level by level from leaf to root).
- 思路:
依然是层序遍历,但是要求输出位先输出最底层,最后输出最上层(逆层序)。解决方法与Leetcode102问题相同,只是首先将存储每层结果的vector对象放入一个栈中,然后出栈存入结果vector中,返回即可。
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int> > res;
if (!root)
return res;
stack<vector<int> > stk;
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
vector<int> sub_vec;
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* node = que.front();
que.pop();
sub_vec.push_back(node->val);
if (node->left)
que.push(node->left);
if (node->right)
que.push(node->right);
}
stk.push(sub_vec);
}
while (!stk.empty()) {
res.push_back(stk.top());
stk.pop();
}
return res;
}
Leetecode 103
103. Binary Tree Zigzag Level Order Traversal
Given a binary tree, return the zigzag level order traversal of its nodes’ values. (ie, from left to right, then right to left for the next level and alternate between).
- 思路:
二叉树的“之”字型层序遍历。应为是层序遍历,所以应该使用queue数据结构,同时由于要满足“之”字型,因此使用deque数据结构,通过从两边分别插入和取出数据来实现。
- 设计一个flag变量,实现切换功能。
- 当flag为true时,从deque的前部获取数据,从后部插入数据,且插入顺序为先左子树后右子树;
- 当flag为false时,从deque的后部获取数据,从前部插入数据,且插入顺序为先右子树后左子树;
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int> > res;
if (!root)
return res;
deque<TreeNode*> dq;
dq.push_front(root);
bool flag = true;
while (!dq.empty()) {
vector<int> sub_vec;
int size = dq.size();
for (int i = 0; i < size; ++i) {
if (flag) { // get front and push back
TreeNode* node = dq.front();
sub_vec.push_back(node->val);
dq.pop_front();
if (node->left) {
dq.push_back(node->left);
}
if (node->right) {
dq.push_back(node->right);
}
} else { // get back and push front
TreeNode* node = dq.back();
sub_vec.push_back(node->val);
dq.pop_back();
if (node->right) {
dq.push_front(node->right);
}
if (node->left) {
dq.push_front(node->left);
}
}
}
res.push_back(sub_vec);
flag = !flag;
}
return res;
}
Leetecode 199
199. Binary Tree Right Side View
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
- 思路:
通过层序遍历,每层只返回最右边的节点值即可。
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
if (!root)
return res;
queue<TreeNode*> que;
que.push(root);
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; ++i) {
TreeNode* node = que.front();
que.pop();
if (i == size - 1)
res.push_back(node->val);
if (node->left)
que.push(node->left);
if (node->right)
que.push(node->right);
}
}
return res;
}
Leetecode 279
279. Perfect Squares
Given an integer n, return the least number of perfect square numbers that sum to n.
A perfect square is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example, 1, 4, 9, and 16 are perfect squares while 3 and 11 are not.
Example 1:
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
- 思路:
转化为求最短路径问题,使用queue数据结构通过层序遍历来求解。用n逐个减掉平方数得到的差值的替代n的值,同时数值不断减小,直到为0表示问题解决。每层数据表述n与平方数之差,通过queue来存储。使用set数据结构来记录已经遇到的差值,该差值不再放入队列中,从而降低计算复杂度。
int numSquares(int n) {
if (!n)
return 0;
queue<int> diffs;
set<int> has_in;
int level = 0;
diffs.push(n);
while (!diffs.empty()) {
int size = diffs.size();
level++;
for (int i = 0; i < size; ++i) {
int diff = diffs.front();
diffs.pop();
for (int k = 1; k * k <= diff; ++k) {
int new_diff = diff - k * k;
if (new_diff == 0)
return level;
if (!has_in.count(new_diff)) {
has_in.insert(new_diff);
diffs.push(new_diff);
}
}
}
}
return 0;
}
Leetecode 127
127. Word Ladder
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words such that:
The first word in the sequence is beginWord.
The last word in the sequence is endWord.
Only one letter is different between each adjacent pair of words in the sequence.
Every word in the sequence is in wordList.
Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord, or 0 if no such sequence exists.
Example 1:
Input: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
Output: 5
Explanation: One shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog” with 5 words.
- 思路:
该题目要求从beginWord到endWord寻找一条最短变化路径(每次改变单次的一个字母)。因为是寻找最短路径问题,因此自然想到的是基于queue的BFS算法。
事实上,该问题可以首先通过wordList建立一个连通图,使用连通矩阵描述改图的连通性,如果两个单次仅相差一个字母,那么就将该两个单词定义为连通。但是该方法当wordList中单词较多时会耗费大量时间。由于该题目仅要求获取最短路径的长度,没有要求获得所有路径,因此可以不建立连通图。
- 实现一个转换判别函数
checkTransform()
,通过判断两个单词之间是否只相差一个字母来判别两个单次是否满足转换条件; - 建立一个queue对象,从beginWord开始将wordList中满足
checkTransform()
同时又没有遇到过的单词压入queue中,从而进行BFS算法; - 每进行一次2中的迭代,count数增加1;如果一开始endWord不在wordList中,那么直接返回0;如果queue对象在运行中出现empty则说明使用wordList中的单次无法完成转换过程,统一返回0;
bool checkTransform(const string& word1, const string& word2) {
if (word1.size() != word2.size())
return false;
int size = word1.length();
int count = 0;
for (int i = 0; i < size; ++i) {
if (word1.at(i) != word2.at(i))
count++;
}
if (count != 1)
return false;
else
return true;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordSet(wordList.begin(), wordList.end());
if (!wordSet.count(endWord))
return 0;
unordered_set<string> processedWords;
queue<string> que;
que.push(beginWord);
int count = 1;
while (!que.empty()) {
int size = que.size();
//cout << "queue size: " << size << endl;
count++;
cout << count << endl;
for (int i = 0; i < size; ++i) {
string str = que.front();
que.pop();
for (const auto& word: wordSet) {
//cout << "see <" << word << ">." << endl;
if (checkTransform(str, word) && !processedWords.count(word)) {
if (word == endWord)
return count;
que.push(word);
processedWords.insert(word);
//cout << "push <" << word << "> into queue." << endl;
}
}
}
}
return 0;
Leetecode 347
347. Top K Frequent Elements
Given a non-empty array of integers, return the k most frequent elements.
Your algorithm’s time complexity must be better than O(n log n)
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
- 思路:
此问题要求时间复杂度小于O(nlog(n)),因此如果通过常用排序算法,那么至少需要O(nlog(n))的时间复杂度。通过使用优先队列,可实现自动排序,同时插入时间复杂度为O(log(n)),此时队列长度为k, 因此时间复杂度为O(log(k)),考虑对nums的遍历操作,总体时间复杂度为O(nlog(k)),可以满足要求。
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
// get frequence
unordered_map<int, int> hmap; // int -> frequence
for (auto num: nums) {
hmap[num]++;
}
// priority-queue by keeping k elems
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pque;
for (auto iter = hmap.begin(); iter != hmap.end(); ++iter) {
if (pque.size() == k) { // has k elem in que, pop() before push()
if (iter->second > pque.top().first) { // push new elem
pque.pop(); // pop smallest elem
pque.push(make_pair(iter->second, iter->first)); // (frequence, int)
}
} else // push directly
pque.push(make_pair(iter->second, iter->first));
}
// output to vector
while(!pque.empty()) {
res.push_back(pque.top().second);
pque.pop();
}
return res;
}
Leetecode 23
23. Merge k Sorted Lists
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
1->4->5,
1->3->4,
2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6
- 思路:
多路归并,且每一路都已经完成排序。可以使用优先队列来完成。本问题要求从小到大排列,所以使用小顶堆, 首先将每路第一个节点加如队列中,然后取出top元素(最小元素)放入结果链表中,再加入该元素在原链表中的下一个元素,直到优先队列为空。
// 构造最小堆
// 返回true时,b处于顶部
struct cmp {
bool operator() (ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, cmp> p_que; // 优先队列(最小堆)
for (int i = 0; i < lists.size(); ++i) {
if (lists[i])
p_que.push(lists[i]);
}
ListNode* head = nullptr;
ListNode* curr = head;
while (!p_que.empty()) {
ListNode* node = p_que.top();
p_que.pop();
if (!curr) {
head = node;
} else {
curr->next = node;
}
curr = node;
if (node->next)
p_que.push(node->next);
}
return head;
}