题目:20. 有效的括号 - 力扣(LeetCode
思路:
1.第一种情况左括号多了:字符串遍历结束,如果栈中元素不为空,证明左括号多了。
2.第二种情况右括号多了:当栈为空,此时字符串遍历还未结束说明右括号多了。
3.第三种情况左右括号不匹配:栈顶元素和字符串中元素未匹配,证明左右括号未匹配上。
4. 第四种情况左右括号匹配:栈为空。
代码:
class Solution {
public:
bool isValid(string s) {
stack<char> st;
if(s.size() % 2 != 0) return false;
for(int i = 0; i < s.size(); i++){
if(s[i] == '('){
st.push(')');
}else if(s[i] == '{'){
st.push('}');
}else if(s[i] == '['){
st.push(']');
//2.第二种情况右括号多了:当栈为空,此时字符串遍历还未结束说明右括号多了,返回false;
//3.第三种情况左右括号不匹配:栈顶元素和字符串中元素未匹配,证明左右括号未匹配上,返回false.
}else if(st.empty() || s[i] != st.top()){
return false;
}else{
st.pop();//左右括号匹配上了,直接弹出栈里的元素
}
}
return st.empty();//1.此时字符串遍历结束,如果栈中元素不为空,证明左括号多了,
//属于第一种情况左括号多了,返回false;如果为空,证明左右括号都匹配上了,返回true.
}
};
题目:1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)
思路:
1.建立一个栈,用来存放我们遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下我们是不是遍历过相同数值的相邻元素,然后再去做对应的消除操作。
2.最后从栈里弹出的时候,由于弹出的字符串是逆序的,所以需要反转一下。
代码:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
string res = "";
for(int i = 0; i < s.size(); i++){
if(st.empty() || s[i] != st.top()){//如果栈为空,直接往栈里添加元素;如果不为空,则判断栈顶元素和此时遍历的元素是否相等
st.push(s[i]);
}else{
st.pop();
}
}
while(!st.empty()){
res += st.top();
st.pop();
}
reverse(res.begin(), res.end());
return res;
}
};
题目:150. 逆波兰表达式求值 - 力扣(LeetCode)
思路:
1.逆波兰表达式相当于是二叉树中的后序遍历,其实总体思路和上一道题删除字符串中所有相邻重复项一样,建立一个栈,如果不是操作符就入栈;如果遇见操作符,如+,-,*,/,就把栈顶元素num1和栈顶元素后一个元素num2依次弹出,操作这两个num,比如遇见+,就计算num2 + num1,并把计算得到的结果再次压入栈,最后栈中剩下的元素就是表达式求值的结果,直接返回。
代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> st;
for(int i = 0; i < tokens.size(); i++){
if(tokens[i] == "+" || tokens[i] == "-" ||
tokens[i] == "*" || tokens[i] == "/"){
long long num1 = st.top();
st.pop();
long long num2 = st.top();
st.pop();
if(tokens[i] == "+") st.push(num2 + num1);
if(tokens[i] == "-") st.push(num2 - num1);
if(tokens[i] == "*") st.push(num2 * num1);
if(tokens[i] == "/") st.push(num2 / num1);
}else{
st.push(stoll(tokens[i]));
}
}
return st.top();
}
};
题目:239. 滑动窗口最大值 - 力扣(LeetCode)
思路:
使用deque设计一个由大到小的单调队列,队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
设计单调队列的时候,pop,和push操作要保持如下规则:
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
具体分析见:代码随想录 (programmercarl.com)
代码:
class Solution {
private:
class MyQueue{//单调队列,由大到小
public:
deque<int> que;//使用deque来实现单调队列
// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
// 同时pop之前判断队列当前是否为空。
void pop(int value){
if(!que.empty() && value == que.front()){
que.pop_front();
}
}
// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
// 这样就保持了队列里的数值是单调从大到小的了。
void push(int value){
while(!que.empty() && value > que.back()){//注意这里是while不是if,因为这是一个不断弹出的过程
que.pop_back();
}
que.push_back(value);
}
// 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
int front(){
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> res;
// 先将前k的元素放进队列
for(int i = 0; i < k; i++){
que.push(nums[i]);
}
res.push_back(que.front());//记录前k个元素中的最大值
for(int i = k; i < nums.size(); i++){
que.pop(nums[i - k]);// 滑动窗口移除最前面元素
que.push(nums[i]);// 滑动窗口前加入最后面的元素
res.push_back(que.front());// 记录对应的最大值
}
return res;
}
};
题目:347. 前 K 个高频元素 - 力扣(LeetCode)
思路:
1.要统计元素出现频率:使用unordered_map统计数组元素出现的频率,key存放元素值,value存放元素出现的频率。
2.对频率排序:使用小顶堆对频率进行排序,得到前k个高频元素,可以使用优先级队列priority_queue来排序,至于为什么用小顶堆,不用大顶堆,是因为大顶堆每次弹出的都是频率最高的那个元素,那么最后剩下的k个元素就是频率最低的k个元素,所以使用小顶堆。
3.找出前K个高频元素:最后建立一个数组vector,倒序输出到数组中。
具体分析见:代码随想录 (programmercarl.com)
代码:
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;
//数组nums元素频率统计,key = nums[i] value = nums[i]出现的频率
for(int i = 0; i < nums.size(); i++){
map[nums[i]]++;
}
// 对频率排序
// 定义一个小顶堆,大小为k,小顶堆是一颗完全二叉树,父结点的值小于等于孩子结点的值
//优先级队列底层实现是一个堆(heap)
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> que;
for(unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++){
que.push(*it);
if(que.size() > k){// 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
que.pop();//每次弹出的是频率最小的
}
}
//经过小顶堆排序后,得到了出现频率前k高的元素
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
vector<int> res(k, 0);
for(int i = k - 1; i >= 0; i--){
res[i] = que.top().first;
que.pop();
}
return res;
}
};