150. 逆波蘭表示式求值
題目連結:https://leetcode.cn/problems/evaluate-reverse-polish-notation/
題目難度:中等
文章講解:https://programmercarl.com/0150.逆波蘭表示式求值.html
影片講解:https://www.bilibili.com/video/BV1kd4y1o7on
題目狀態:多次修改 bug 後透過
個人思路:
透過棧進行解決。
先判斷佇列中的元素是否為數字型別。若為數字型別,壓入棧;若不是數字型別,則肯定是運算子,使用switch
結構進行運算,將棧中的頭兩個元素彈出,進行運算子運算,運算後將結果在壓入棧中。最後返回棧頂元素。
修改 bug 的過程:
- 棧的空間:當棧內有兩個或兩個以上的元素的時候才能進行運算子運算。
- 符號判斷:在判斷佇列元素是否為數字的時候,忘記還有負數這一項,需要先判斷元素的第一個元素是否為
-
且元素是否含有多個元素,若是,則從元素中的下一個元素判斷是否為數字;若不是,則直接判斷。
程式碼實現:
class Solution {
public:
bool isNum(const string &s) {
if(s[0] == '-' && s.size() > 1) {
for(int i = 1; i < s.size(); ++i) {
if(!isdigit(s[i])) return false;
}
} else if(s[0] == '-' && s.size() == 1) {
return false;
} else {
for(auto &elem: s) {
if(!isdigit(elem)) return false;
}
}
return !s.empty();
}
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(auto &token: tokens) {
if(isNum(token)) {
st.push(stoi(token));
}
else if(!st.empty() && st.size() >= 2){
int op1 = st.top(); st.pop();
int op2 = st.top(); st.pop();
int res = 0;
switch(token[0]) {
case '+': res = op2 + op1; break;
case '-': res = op2 - op1; break;
case '*': res = op2 * op1; break;
case '/': res = op2 / op1; break;
}
st.push(res);
}
}
return st.top();
}
};
239. 滑動視窗最大值
題目連結:https://leetcode.cn/problems/sliding-window-maximum/
題目難度:困難
文章講解:https://programmercarl.com/0239.滑動視窗最大值.html
影片講解:https://www.bilibili.com/video/BV1XS4y1p7qj
題目狀態:有思路,但敗在了超時上,學習到了單調佇列
思路:
一開始想,啊?困難題就這?根本難不倒我,最後卻在編譯的過程中敗在了超時上,而且毫無思路去最佳化,最後學習了單調數列,利用單調數列解決這個問題異常輕鬆。
先看動圖理解以下思路:
單調佇列的構建:
- 首先建立一個
MyQue
類來實現單調函式,分別有三個函式:pop()
、push()
、front()
; push()
:這個不是簡單的 push,當單調佇列中存在的元素小於要 push 的元素,就需要將它們都彈出佇列(使用pop_back()
,因為從佇列的back
開始遍歷的),而把要 push 的元素 push 進來。此時,單調佇列中的隊頭就是 push 進來的最大元素。pop()
:當要彈出佇列元素的時候,要彈出的元素小於隊頭元素時,表明這個元素早已在 push 的時候已經被彈出佇列,不需要進行任何操作,只有當彈出元素和隊頭元素相等的時候,才需要把隊頭元素彈出(使用pop_front()
,因為隊頭在佇列的front
處)。front()
:這個就是返回單調佇列的隊頭元素,也是此時佇列中最大的一個元素。
透過構建的單調佇列實現滑動視窗中的最大值,視窗每滑動一次,就需要把對應的左邊元素從單調佇列中pop
出來,在把對應的右邊的元素push
到單調佇列中去。每滑動一次,就使用一個陣列去記錄單調佇列中的隊頭元素(因為這個元素時此時滑動視窗中的最大值),最後返回陣列即可。
程式碼實現:
class Solution {
public:
class MyQueue {
public:
void pop(int value) {
if(!_que.empty() && value == _que.front()) _que.pop_front();
}
void push(int value) {
while(!_que.empty() && value > _que.back()) _que.pop_back();
_que.push_back(value);
}
int front() {
return _que.front();
}
private:
deque<int> _que;
};
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue mq;
vector<int> res;
for(int i = 0; i < k; ++i) {
mq.push(nums[i]);
}
res.push_back(mq.front());
for(int i = k; i < nums.size(); ++i) {
mq.pop(nums[i - k]);
mq.push(nums[i]);
res.push_back(mq.front());
}
return res;
}
};
347. 前 K 個高頻元素
題目連結:https://leetcode.cn/problems/top-k-frequent-elements/
題目難度:中等
文章講解:https://programmercarl.com/0347.前K個高頻元素.html
影片講解:https://www.bilibili.com/video/BV1Xg41167Lz
題目狀態:有思路,透過 ChatGPT 最佳化程式碼後透過
個人思路:
建立一個map
,來儲存字串中出現的每個元素對應的次數,然後對map
的值進行排序,獲得前k
個元素的鍵,前k
個鍵就是字串中前k
個高頻元素。
程式碼實現:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> countMap;
for(auto &num : nums) countMap[num]++;
vector<pair<int, int>> freq(countMap.begin(), countMap.end());
sort(freq.begin(), freq.end(), [](const pair<int, int> &a, const pair<int, int> &b){ return a.second > b.second; });
vector<int> res;
for(int i = 0; i < k; ++i) {
res.push_back(freq[i].first);
}
return res;
}
};
優先順序佇列的思想:
透過小頂堆記錄前k
個頻率的元素,每次小頂堆會將最小的元素彈出,最後小頂堆裡積累的就是前k
個最大元素。
程式碼實現(有點沒看懂):
class Solution {
public:
// 小頂堆
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
// 要統計元素出現頻率
unordered_map<int, int> map; // map<nums[i],對應出現的次數>
for (int i = 0; i < nums.size(); i++) {
map[nums[i]]++;
}
// 對頻率排序
// 定義一個小頂堆,大小為k
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
// 用固定大小為k的小頂堆,掃面所有頻率的數值
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) { // 如果堆的大小大於了K,則佇列彈出,保證堆的大小一直為k
pri_que.pop();
}
}
// 找出前K個高頻元素,因為小頂堆先彈出的是最小的,所以倒序來輸出到陣列
vector<int> result(k);
for (int i = k - 1; i >= 0; i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};