简单:
232 用栈实现队列
https://leetcode.cn/problems/implement-queue-using-stacks/submissions/
解答:
思路:用两个栈来实现,倒一下即刻。
class MyQueue {
public:
stack<int> in;
stack<int> out;
MyQueue() {
}
void push(int x) {
in.push(x);
}
int pop() {
if(out.empty()){
while(!in.empty()){
out.push(in.top());
in.pop();
}
}
int reslut = out.top();
out.pop();
return reslut;
}
int peek() {
int reslut = this->pop();
out.push(reslut); //因为pop函数弹出了元素res,所以再添加回去
return reslut;
}
bool empty() {
return in.empty() && out.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
225. 用队列实现栈
解答:
思路:
两个队列来实现栈。其中一个队列是用来暂存数据的。也就是先将队列1中的元素都放到队列2中,只留下最后一个元素作为输出,然后在讲队列2中的元素放回队列1后,将队列2清空;反复此操作。
class MyStack {
public:
queue<int> q1;
queue<int> q2;
MyStack() {
}
void push(int x) {
q1.push(x);
}
int pop() {
int size=q1.size();
while(size!=1){
q2.push(q1.front());
q1.pop();
size--;
}
int result=q1.front();
q1.pop();
q1=q2;
while(!q2.empty()){
q2.pop();
}
return result;
}
int top() {
return q1.back(); //返回最末元素
}
bool empty() {
return q1.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
20. 有效的括号
解答:
思路:
碰见一个左括号,就将其对应的右括号放进栈中。如果栈为空,或者遍历到的右括号不等于栈顶元素,那就是false。如果左括号找到了对应的右括号,就弹出栈即可。
代码:
class Solution {
public:
bool isValid(string s) {
stack<int> tmp;
for(int i=0;i<s.size();i++){
if(s[i]=='(') tmp.push(')');
else if(s[i]=='{') tmp.push('}');
else if(s[i]=='[') tmp.push(']');
else if(tmp.empty() || s[i]!=tmp.top()) return false;
else
tmp.pop();
}
return tmp.empty();
}
};
1047. 删除字符串中的所有相邻重复项
解答:
法一:
思路:将字符串本身当作栈。将字符放入栈中,比较栈顶元素和外面遍历的元素是否相等,相等就弹出栈,不相等就将栈外元素压入栈。当然如果是第一个元素,就直接讲该元素压入栈。最后返回就返回该作为栈的字符串即可。
class Solution {
public:
string removeDuplicates(string s) {
string tmp;
for(int i=0;i<s.size();i++)
{
if(tmp.empty() || tmp.back()!=s[i])
{
tmp.push_back(s[i]);
}
else {
tmp.pop_back();
}
}
return tmp;
}
};
法二
思路:新创建一个字符类型的栈,与法一同样原理,外面遍历的元素如果和栈顶元素相等,就弹出栈顶元素。这样输出的时候,不能直接输出栈,因为返回值类型不同,需要将栈中的元素取出(此时是反序的),再逆序。
代码:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> tmp;
for(int i=0;i<s.size();i++)
{
if(tmp.empty() || tmp.top()!=s[i])
{
tmp.push(s[i]);
}
else {
tmp.pop();
}
}
string result="";
while(!tmp.empty()){
result += tmp.top();
tmp.pop();
}
reverse (result.begin(), result.end()); // 反转
return result;
}
};
150. 逆波兰表达式求值
思路:与上一题的思路是一样的,只是不移除元素,将栈顶两个元素弹出,做相应的运算,然后再将运算后的结果放回栈中,最终要的结果就是栈顶元素。(记得要类型转换string->int)
代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> tmp;
for(int i=0;i<tokens.size();i++){
if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/" ){
int a1=tmp.top();
tmp.pop();
int a2=tmp.top();
tmp.pop();
if(tokens[i] == "+" ){
tmp.push(a1+a2);
}
else if(tokens[i] == "-" ){
tmp.push(a2-a1);
}
else if(tokens[i] == "*" ){
tmp.push(a1*a2);
}
else if(tokens[i] == "/" ){
tmp.push(a2/a1);
}
}
else{
tmp.push(stoi(tokens[i])); // stoi()函数为string.h中的,将string类型转化为int类型
}
}
return tmp.top();
tmp.pop();
}
};
239. 滑动窗口最大值
解答:
思路:
总思路:在双向队列中,只存放k个数据(这个数据是nums中元素对应的索引),并且这写数据是递减排序的,每次取出开头front的数据即为最大数据。
过程:
1、创建一个双向队列,因为双向队列对前端数据和后端数据可以进行弹出操作。
2、判断是否在滑动范围内。
3、保证队列是递减队列,即如果当前的数据比队列中最后一个位置对应的数据还要大,那就说明最后一个(back)元素不可能是最大元素,就弹出;然后再重复此过程,判断它(back)前面的数据是否小于当前数据,小于,就还弹出。
4、将当前元素对应的位置(索引)放进队列。
5、判断队列中是否已经达到了k个元素,到了就该取最大值了,也就是队列第一个元素对应的数据。
代码:
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> d; //创建双向队列
vector<int> result;
for(int i=0;i<nums.size();i++){
while(d.size() && i-k+1>d.front()) {d.pop_front();} //判断是否在滑动范围内。
while(d.size() && nums[i]>=nums[d.back()]) {d.pop_back();} //保证队列是递减队列
d.push_back(i);
if(i>=k-1){result.push_back(nums[d.front()]);}//判断队列中是否已经达到了k个元素,到了就该取最大值了
}
return result;
}
};
347. 前 K 个高频元素
解答:
思路:
1、首先涉及到需要存到一个值和其对应的频率,可以想到可以用map来存放。所以首先使用一个无序的map把数组中的值及其对应的频率保存起来。
2、其次需要根据这些频率进行排序,并输出值。可以想到大顶堆和小顶堆来做。此时我们选用小顶堆,此时为了方便,可以直接使用priority_queue优先队列来存放(该队列优先级最高的先弹出)。
涉及到的基础知识罗列:
1、operator重载运算符
语法:
函数类型 operator 运算符名称(或操作符)(参数列表)
{
函数体;
}
2、priority_queue优先队列
优先级高的元素先出队列,并非按照先进先出的要求.类似一个堆(heap).
priority_queue<Type, Container, Functional>
Type:数据类型
Container:为保存数据的容器
Functional:为元素比较方式
3、unordered_map
无序映射(Unordered maps)是用于存储键值和映射值组合成的元素的关联容器,并允许基于其键快速检索各个元素。
在unordered_map中,键值通常用于唯一地标识元素,而映射值是具有与该键关联的内容的对象。键的类型和映射的值可能会有所不同。
头文件:
#include < unordered_map >
代码:
class Solution {
public:
//构造小顶堆
class compare_Function{
public:
bool operator()(const pair<int,int>& p1,const pair<int,int>& p2){
return p1.second>p2.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map <int,int> map;
for(int i=0;i<nums.size();i++){
map[nums[i]]++; //用来存放每个数据的频率
}
priority_queue<pair<int,int>,vector<pair<int,int>>,compare_Function> que;
for(unordered_map<int,int>::iterator it=map.begin();it!=map.end();it++){
que.push(*it);
if(que.size()>k){
que.pop();
}
}
//由于是小顶堆,需要倒序输出
vector<int> result(k);
for(int i=k-1;i>=0;i--){
result[i]=que.top().first;
que.pop();
}
return result;
}
};