栈_leetcode

T1: 设计一个 包含 取到min值函数 的 栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

解:

1.关键:

(1)借用 了 讨论区的 思想: 再存入 新的元素 x之前, 先把 前一个min_val 存到栈 里面 , 然后 更新min_val

(2)出栈 的时候 ,pop-> 更新 min_val ->pop

(3)直接返回min_val数据成员即可

2.代码:

class MinStack {
public:
    //自己利用 而二进制序列定义 有符号 整数 最大值
    const int  MAX_INT = 0x7fffffff; //4个字节 , 8个十六进制数字
    int min_val=MAX_INT; //这个就可以取到 整数的 最大值
    stack St;
    //妙啊, 借助 讨论区的 思想, 每次先存上一次的 最小值, 然后 再存 x
    //每次pop ,都要pop两次
    /** initialize your data structure here. */
    MinStack() {

    }
    
    void push(int x) {
        St.push(min_val);
        //先加入 “上一次 最小值”
        if(x < min_val)
        {
            min_val = x;
        }
        //入栈
        
        St.push(x);
    }
    
    void pop() {
        //出栈:
        St.pop();
        min_val = St.top(); // 更新 min_val
        St.pop();
    }
    
    int top() {
        return St.top();
    }
    
    int min() {
        //反正不会 再 空栈的 时候调用
        return min_val;
    }
};

T2:用2个栈 实现 队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

解:

1.关键:

(1)一个“输入栈” 一个“输出栈”

(2)入队 ,直接加入到 “输入栈”即可

(3)出队,如果“输出栈”还有元素 ,那就直接“输出栈”出栈即可, 否则 ,转存,然后stack2出栈

2.代码:

class CQueue {
public:
    //最朴素的方法 就是 将stack1中的元素 倒序 存储到stack2中
    //其实 就是 一个“输入栈” + 一个“输出栈”
    //push都加入到stack1中 ,pop都从stack2中pop即可,nice
    stack stack1;
    stack stack2;
    CQueue() {

    }
    
    void appendTail(int value) {
        //加入一个 尾部元素 , 直接存储到 stack1中即可
        stack1.push(value);
        //删除元素的时候 才需要 将stack1 倒序存储到 stack2中
    }
    
    int deleteHead() {
        //每次必须先把 之前的 stack2中的元素 全部删除才行
        if(stack2.empty())
        {
            if(stack1.empty())
            {
                return -1;
            }
            else
            {
                put(); // 转存
            }
        }
        int tmp =stack2.top();
        stack2.pop();
        return tmp;
        
    }
    void put()
    {
        while(!stack1.empty())
        {
            int tmp = stack1.top();
            stack1.pop();
            stack2.push(tmp);
        }
    }
};

T3:"三合一" 一个vector 作为 3个stack使用

三合一。描述如何只用一个数组来实现三个栈。

你应该实现push(stackNum, value)pop(stackNum)isEmpty(stackNum)peek(stackNum)方法。stackNum表示栈下标,value表示压入的值。

构造函数会传入一个stackSize参数,代表每个栈的大小。

解:

1.关键:

(1)主要是 处理 下标的 问题:

<1>每个stack的大小为size, 但是 这个vector分配了1+3*(size+1),也就是从1开始用,然后 每个stack有一个判断为空栈的不使用的位置

<2>栈空 坐标:index[stackNum] == stackNum*size+stackNum+1

<3>栈满 坐标:size+1 = (i+1)*size +(i+1)

2.代码:

class TripleInOne {
public:
    //利用 一个 vec 实现 3个 stack ,主要是 处理下标的问题
    vector vec;
    int size=0;
    //int index1=1,index2=0,index3=0; // 标记3个栈顶的 位置
    int index[3];
    TripleInOne(int stackSize) {
        //构造函数
        //每个栈的 大小 都是stackSize+1 , 空-第一个位置, 满-最后一个位置
        vector tmp(3*(stackSize+1)+1,0); // 从下标1开始用
        vec = tmp;
        index[0] = 1; //栈 满 位置: size+1 = (i+1)*size +(i+1)
        index[1] = stackSize+2; //满:2*size+2
        index[2] = 2*stackSize+3; // 满 3*size+3
        size = stackSize;
    }
    
    void push(int stackNum, int value) {
        //(1)如果 栈满 不如栈:
        if(index[stackNum] == (stackNum+1)*(size+1))
        {
            return ;
        }
        //入栈
        index[stackNum]++;
        vec[index[stackNum]] = value;
    }
    
    int pop(int stackNum) {
        if(isEmpty(stackNum))
        {
            return -1;
        }
        int tmp = vec[index[stackNum]];
        index[stackNum]--;
        return tmp;
    }
    
    int peek(int stackNum) {
        //返回栈顶 元素
        if(isEmpty(stackNum))
        {
            return -1;
        }
        return vec[index[stackNum]];
    }
    
    bool isEmpty(int stackNum) {
        //判断 栈 空:
        if(index[stackNum] == stackNum*size+stackNum+1)
        {
            return true;
        }
        return false;
    }
};

T4:递归实现汉诺塔问题(本质上是 栈结构)

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

解:

1.关键:

(1)添加一个参数 n,表示要移动的 元素的个数

(2)注意,vec中 后面 指“上面”

(3)由于可以利用 pop_back() 和 back()函数 从后处理 vector,所以直接传递 vector的引用即可

2.代码:

class Solution {
public:
    void hanota(vector& A, vector& B, vector& C) {
        //其实 用递归写 这个函数 并不难 ,不过需要添加一个 参数n
        int size= A.size();
        move(size,A,B,C);
    }
    void move(int n ,vector& A,vector& B,vector& C)
    {
        //(1)出口
        if(n==1)
        {
            //直接将A上的那个元素 移动到 C上即可
            C.push_back(A.back());
            A.pop_back();
            return ;
        }
        //(2)递归:
        //先借助C将n-1个元素 移动到 B
        //然后 将 A最后一个元素移动到 C
        //最后借助A将n-1的元素 从B移动到C
        move(n-1,A,C,B);
        C.push_back(A.back());
        A.pop_back();
        move(n-1,B,A,C);
    }
};

T5:找出 二叉搜索树(BST)中的所有 众数

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

解:

1.关键:

(1)必然需要遍历一次 所有的节点(就利用 先序遍历的 递归形式即可)

(2)再遍历的 同时 将 访问节点 改为 存储到Map中的 次数, 并且不断 更新当前的 做大出现次数max

(3)最后遍历一个Map找出所有 出现次数 == max的 元素 

2.代码:

class Solution {
public:
    unordered_map Map;
    int max =0;
    vector findMode(TreeNode* root) {
        //(1)必然需要遍历一次
        //(2)然后利用map 记录 每个数值出现的次数,并且记录当前最大次数 max
        //(3)再遍历一个map,从而得到所以 出现次数 等于 max的数值
        travel(root);
        //利用 先序遍历, 递归形式
        vector ans;
        //遍历一次 map
        for(auto &[v1,v2]: Map)
        {
            if(v2 == max)
            {
                ans.push_back(v1);
            }
        }
        return ans;
    }
    void travel(TreeNode* root)
    {
        //(1)出口:
        if(root == NULL)
        {
            return ;
        }
        //先访问该节点 , 加入到 map中 , 并且比较 max的数值
        Map[root->val]++;
        if(Map[root->val] > max)
        {
            max = Map[root->val];
        }
        //递归 ,先访问 左节点, 然后 访问 右节点
        travel(root->left);
        travel(root->right);
    }
};

T6:填充 一个 完美二叉树的 节点的 “层序遍历 右侧 指针next”

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

初始状态下,所有 next 指针都被设置为 NULL

解:

1.关键:

(1)由于 出队 和 入队的 关系容易混乱 ,这里 我才用 2个队列 交替使用, 一个队列负责 元素的 出队 ,同时 另一个队列 负责元素的 入队

(2)利用 bfs 广搜函数 和 update函数 :

<1>bfs 函数 : 负责 判断 2个队列 是否 同时 为空 -- 作为 结束点, 同时交替 叫用 update函数

<2>update函数: 负责 更新2个队列, 先从非空队列 中 取出元素 ,然后 将新的left , right节点 存到另一个队列中

2.代码:

class Solution {
public:
    int flag=0;
    Node* connect(Node* root) {
        //bfs层序遍历 ,每个节点的 next指针 指向 这一层 右边的 节点
        //而且这就是那个改进版本的 bfs 广搜,因为需要考虑每一层的最后一个节点的next
        bfs(root);
        return root;
    }
    void bfs(Node* root)
    {
        //创建2个队列 , 我记得 就是这样的,2个队列交替使用
        //每次 访问完一个 队列的同时 ,把新的 节点元素 添加到 另外一个队列中
        queue Que1;
        queue Que2;
        Que1.push(root);
        while(!(Que1.empty() && Que2.empty()))
        {
            if(flag == 1)
            {
                return ;
            }
            //(1)Que1非空
            if(!Que1.empty())
            {
                update(Que1,Que2); 
            }

            //(2)Que2非空
            else if(!Que2.empty())
            {
                update(Que2,Que1);
            }
        }
    }
    void update(queue& Q1 , queue& Q2)//取出Q1,存入Q2
    {
        Node* tmp = Q1.front();
        if(tmp == NULL)
        {
            flag =1 ;
            return ;
        }
        Q1.pop();
        if(tmp->left!=NULL)
        Q2.push(tmp->left);
        if(tmp->right!=NULL)
        Q2.push(tmp->right);
        //负责 更新队列
        while(!Q1.empty())
        {
            //从前 向后 依次 取出所有的节点
            Node* node = Q1.front();
            Q1.pop();  //出队
            tmp->next = node;
            tmp = node;
            //同时 将 left 和 right节点 入队Q2
            if(node->left !=NULL)
            Q2.push(node->left);
            if(node->right != NULL)
            Q2.push(node->right);
        }
        if(tmp!=NULL)
        {
            tmp->next =NULL;
        }
    }
};

T7:将上面 那个题中的 “完全二叉树 ” 改为 “一般二叉树”

给定一个二叉树:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。

初始状态下,所有 next 指针都被设置为 NULL 。

解:

1.关键:

(1)上一题 可以利用 flag 只用 遇到 最后一层的 叶子节点 ,直接 return

(2)这里 考虑  ,把NULL 节点 出队 ,然后 “重进”

2.代码:

class Solution {
public:
    Node* connect(Node* root) {
        //bfs层序遍历 ,每个节点的 next指针 指向 这一层 右边的 节点
        //而且这就是那个改进版本的 bfs 广搜,因为需要考虑每一层的最后一个节点的next
        bfs(root);
        return root;
    }
    void bfs(Node* root)
    {
        //创建2个队列 , 我记得 就是这样的,2个队列交替使用
        //每次 访问完一个 队列的同时 ,把新的 节点元素 添加到 另外一个队列中
        queue Que1;
        queue Que2;
        Que1.push(root);
        while(!(Que1.empty() && Que2.empty()))
        {
            //(1)Que1非空
            if(!Que1.empty())
            {
                update(Que1,Que2); 
            }

            //(2)Que2非空
            else if(!Que2.empty())
            {
                update(Que2,Que1);
            }
        }
    }
    void update(queue& Q1 , queue& Q2)//取出Q1,存入Q2
    {
        Node* tmp = Q1.front();
        if(tmp == NULL)
        {
            Q1.pop();
            return ;
        }
        Q1.pop();
        if(tmp->left!=NULL)
        Q2.push(tmp->left);
        if(tmp->right!=NULL)
        Q2.push(tmp->right);
        //负责 更新队列
        while(!Q1.empty())
        {
            //从前 向后 依次 取出所有的节点
            Node* node = Q1.front();
            Q1.pop();  //出队
            tmp->next = node;
            tmp = node;
            //同时 将 left 和 right节点 入队Q2
            if(node->left !=NULL)
            Q2.push(node->left);
            if(node->right != NULL)
            Q2.push(node->right);
        }
        if(tmp!=NULL)
        {
            tmp->next =NULL;
        }
    }
};

T8:利用 stack栈 得到 按照 逆波兰顺序存储的 表达式的 结果

根据 逆波兰表示法,求该后缀表达式的计算结果。

有效的算符包括 +-*/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

解:

1.关键:

(1)利用 一个 stack  作为 工具

(2)遍历 vector ,分2种情况:

case1: 运算符 , 从stack中!!按次序 取出 num1 和 num2 ,注意 - 和 / 运算的次序,存入结果

case2: 整数, 直接存储到 stack中即可

2.代码:

class Solution {
public:
    int evalRPN(vector& tokens) {
        //利用 stack 栈实现 后缀 表达式 --逆波兰 表达式
        //(1)如果 是一个 二元 运算符 , 就将stack中的 2个整数拿出来计算
        //(2) 如果 不是二元 运算符 , 就把它存到栈里面
        //(3)最后栈里面剩下的就是 最终结果
        stack st;
        //遍历依次 这个vec 利用 if进行相关的 判断
        int size = tokens.size();
        for(int i=0;i

T9:栈排序( “单调栈”)

栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:pushpoppeek 和 isEmpty。当栈为空时,peek 返回 -1。

解:

1.关键:

(1)主栈 中 始终 维持 有序的状态, 而 辅助栈 只是作为一个临时 存储的 容器

(2)再 push加入 新的 元素的 时候 ,其实 就好比 插入排序的 思想,: 找到 合适的为止,然后 再把那些 放到 辅助栈 中的元素 由 添加回来

2.代码:

class SortedStack {
public:
    //这里好像一定 要对stack 进行排序 , 否则 每次pop会出问题
    //这和 之前 做过的 一个 单调栈的 问题 好像是一样的
    stack st1; // 主栈 : 里面的 元素都是排序的
    stack st2; //辅助栈
    SortedStack() {

    }
    
    void push(int val) {
        //添加元素,直到 ,让 stack1一直出栈 , 然后 将元素 存到stack2中
        while(!st1.empty() && (val > st1.top()))
        {
            //st1出栈 , st2 入栈
            int tmp = st1.top();
            st1.pop();
            st2.push(tmp);
        }
        st1.push(val);
        while(!st2.empty())
        {
            st1.push(st2.top());
            st2.pop();
        }
    }
    
    void pop() {
        if(st1.empty())
        {
            return ;
        }
        st1.pop();
        
    }
    
    int peek() {
        if(st1.empty())
        {
            return -1;
        }
        return st1.top();
    }
    
    bool isEmpty() {
        return st1.empty();
    }
};

T10:给定一个 入栈次序, 验证 这个出栈次序 是可能的

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

解:

1.关键:

(1)模拟 这个出栈结果是否可能即可

(2) 以 遍历 popped序列:从前往后 遍历 , 每次 “不回头”地到 pushed序列中找

(3)如果 再 pushed序列中 找到了 ,删除这个元素, 并且 下标j--(j为0的时候除外),size1--,

2.代码:

class Solution {
public:
    bool validateStackSequences(vector& pushed, vector& popped) {
        // 这一题 也就是 说 :只要 这个pop的情况能够 实现就 true 否额则false上课题
        //感觉有点 小难 ,也许 模拟可以做到
        //果然 还是 模拟 一个 栈stack的 结构
        //(1)主体 还是 遍历 数组 popped 从前往后 遍历,遇到了一个val
        //然后:就可以对push从前往后遍历 去找那个val,找到了就出去 
        //之后:下一次 可以出栈的元素就是 val前一个元素 和 所有val后面的元素
        int size1 = pushed.size();
        int size2 = popped.size();
        // j 不能回头
        int j=0;
        for(int i=0;i<=size2-1;i++)
        {
            int num = popped[i];
            for( ;j <=size1-1;j++)
            {
                //是否可以 匹配:
                if(pushed[j] == num)
                {
                    //cout<size1-1 &&(pushed.size()))
            {
                return false;
            }
        }
        return true;
    }
};

T11:最大栈,既可以得到最大的元素,又可以让最大的元素出栈

设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。

实现 MaxStack 类:

  • MaxStack() 初始化栈对象
  • void push(int x) 将元素 x 压入栈中。
  • int pop() 移除栈顶元素并返回这个元素。
  • int top() 返回栈顶元素,无需移除。
  • int peekMax() 检索并返回栈中最大元素,无需移除。
  • int popMax() 检索并返回栈中最大元素,并将其移除。如果有多个最大元素,只要移除 最靠近栈顶 的那个。

解:

1.关键:

(1)利用3个栈,一个普通栈存储原来的次序, 排序栈用来存储排序号的栈元素,辅助栈用来进行暂时存储的位置

2.代码:

第一次,最后三个 测试用例超时了, 我采用的是 普通栈 + 排序栈 + 辅助栈(3栈的思路进行代码的)

class MaxStack {
public:
    //既然大家 都这么干, 那我就用 3栈 进行求解了
    stack stack1; //这个栈中的元素都是按 顺序加入 栈中的
    stack stack2; //这个栈中的元素都是 排序好的元素
    stack stack3; //这个栈 是辅助栈,用来更新stack2的
    //最后3个测试 用例超时了,真tm
    MaxStack() {

    }
    
    void push(int x) {
        stack1.push(x); //“真栈”中加入一个新的元素
        //在stack2中找到合适的位置 并且 利用辅助栈(大的元素放到栈顶)
        while((!stack2.empty()) && stack2.top()>x)
        {
            int top_num = stack2.top();
            stack2.pop();
            stack3.push(top_num);
        }
        stack2.push(x);
        while(!stack3.empty())
        {
            int top_num = stack3.top();
            stack3.pop();
            stack2.push(top_num);
        }
    }
    
    int pop() {
        //stack1中直接移除栈顶元素
        int top_num = stack1.top();
        stack1.pop();
        //stack2中,先利用辅助栈找到那个元素 , 然后再出栈
        while(stack2.top() != top_num)
        {
            //--
            int tmp = stack2.top();
            stack2.pop();
            stack3.push(tmp);
        }
        stack2.pop();
        while(!stack3.empty())
        {
            int tmp = stack3.top();
            stack3.pop();
            stack2.push(tmp);
        }
        return top_num;
    }
    
    int top() {
        //直接返回 栈顶元素
        return stack1.top();
    }
    
    int peekMax() {
        return stack2.top();
    }
    
    int popMax() {
        //stack2直接移除最上面的那个元素即可
        int top_num = stack2.top();
        stack2.pop();
        //stack1中:先找到top_num元素 , 然后移除
        while(stack1.top() != top_num)
        {
            int tmp = stack1.top();
            stack1.pop();
            stack3.push(tmp);
        }
        stack1.pop();
        while(!stack3.empty())
        {
            int tmp = stack3.top();
            stack3.pop();
            stack1.push(tmp);
        }
        return top_num;
    }
};

借鉴了 评论区的 思想后,考虑 改用2个栈,一般栈 + 每次加入元素时的最大元素(打擂台的方法进行记录)

虽然还是 超时, 算了 ,有兴趣的 请去看 其它人的题解吧,难受得很

T12:最大频率栈

设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。

实现 FreqStack 类:

  • FreqStack() 构造一个空的堆栈。
  • void push(int val) 将一个整数 val 压入栈顶。
  • int pop() 删除并返回堆栈中出现频率最高的元素。
    • 如果出现频率最高的元素不只一个,则移除并返回最接近栈顶的元素

解:

法一:(比较朴素 直接的 方法 -- 8个测试用例超时了--还是记录一下自己的思考历程)

1.关键:

(1)数据结构部分:

<1>stack1,就是一个 普通的栈结构

<2>map1 , 这个map的结构是记录stack中 出现的元素的次数

(2)入栈部分: stack1中直接入栈,而map1[val]++ , 即可

(3)出栈部分:先遍历map1,将所有出现次数最大的 元素 全部存储到 set1中,然后 从stack1的栈顶 依次 遍历,直到找到一个 元素 在set1中出现过为止 ,接着只要利用 辅助栈 ,将那个元素出栈即可,并且记得map[res]-- ,更新map

2.代码:

class FreqStack {
public:
    //记录 栈中出现次数 最多的元素,并且每次 出栈都是 次数最多的元素出栈
    //如果 次数相同,让接近栈顶的元素 出栈
    //我打算,用一个map 记录 这一个pair
    //可能需要利用map来 寻找那个出现频率最大的元素
    map map1;//就用这种map吧,然后只要找到了,最先在stack中匹配的出栈
    stack stack1;
    FreqStack() {

    }
    
    void push(int val) {
        stack1.push(val);
        //--map1中对应元素出现的次数也要更新
        map1[val]++;
    }
    
    int pop() {
        //遍历map1,找出所有出现频率最高的map,然后,最先在stack中匹配的出栈
        //并且更新map1[val] 出现的次数
        int max=0;
        unordered_set set1; //记录
        for(auto [val,time]:map1)
        {
            if(time > max)
            {
                max = time; //说明最大的次数有变化
                set1.clear();
                set1.insert(val);
            }
            else if(time == max)
            {
                set1.insert(val);
            }
        }
        //好了,现在出现次数 最多的 元素 都在set1中了
        //从栈顶开始 遍历 这个栈
        //利用辅助栈做好记录
        stack stack2;
        while(!set1.count(stack1.top()))
        {
            int tmp = stack1.top();
            stack1.pop();
            stack2.push(tmp);
        }
        int res = stack1.top();
        stack1.pop();
        while(!stack2.empty())
        {
            int tmp = stack2.top();
            stack2.pop();
            stack1.push(tmp);
        }
        //更新map
        map1[res]--;
        return res;
    }
};

法二:利用2个map的数据结构进行求解 (这个是 借鉴答案的思想)

解:

1.关键:

(1)数据结构 map1: 用来 记录 栈中元素出现的次数

                        map2> 用来记录 出现次数为time的 栈,栈里面存有所有的元素

(2)一个精辟的评论:

//有一个问题:为什么不要考虑map[max_time-1]的这个 栈呢?

        //妙处在于,一个数字xxx如果出现了5次,那么在频率1、频率2、……、频率5这五个栈里都有xxx

2.代码:

class FreqStack {
public:
    //借鉴答案的思想, 多个栈 , 2个map
    //map1:记录 从开始以来 所有的 栈中元素 次数
    //map2:>,从某个次数 ,映射一个栈
    //一个打擂台的 记录 最大出现次数的max_time
    int max_time = 0;
    unordered_map map1;
    unordered_map> map2;
    FreqStack() {
        max_time = 0;
    }
    
    void push(int val) {
        //入栈:更新次数
        map1[val]++;
        max_time = max(max_time,map1[val]);
        map2[map1[val]].push(val);
    }
    
    int pop() {
        //出栈:
        //找出 出现次数最大的栈的 栈顶元素 map2[max_time].top()
        //然后利用 更新 
        int target_val = map2[max_time].top();
        map1[target_val]--;
        map2[max_time].pop(); //栈顶元素出栈:
        //如果 map2[max_time]这个栈空了,更新 max_time
        if(map2[max_time].empty())
        {
            max_time--;
        }
        //有一个问题:为什么不要考虑map[max_time-1]的这个 栈呢?
        //妙处在于,一个数字xxx如果出现了5次,那么在频率1、频率2、……、频率5这五个栈里都有xxx
        //这个评论非常精辟
        return target_val;
    }
};

T13:设计一个 支持 增量操作的 栈

请你设计一个支持对其元素进行增量操作的栈。

实现自定义栈类 CustomStack :

  • CustomStack(int maxSize):用 maxSize 初始化对象,maxSize 是栈中最多能容纳的元素数量。
  • void push(int x):如果栈还未增长到 maxSize ,就将 x 添加到栈顶。
  • int pop():弹出栈顶元素,并返回栈顶的值,或栈为空时返回 -1 。
  • void inc(int k, int val):栈底的 k 个元素的值都增加 val 。如果栈中元素总数小于 k ,则栈中的所有元素都增加 val 。

解:

1.关键:

(1)利用 cnt 记录当前 栈 中的 元素 个数 , 利用 max记录 stack容器可以容纳的 最大元素个数

(2)pop 出栈函数的话, 直接出栈,然后更新cnt就好了

(3)inrement函数,将栈底的 k个 元素 +val , 利用 辅助栈 ,在入栈的时候 进行k次 +val的操作即可

2.代码:

class CustomStack {
public:
    stack stack1;
    int cnt=0;
    int max=0;
    CustomStack(int maxSize) {
        max = maxSize;
        cnt = 0 ; //记录当前栈中的元素 数量
    }
    
    void push(int x) {
        //如果 已满,直接return 
        if(cnt == max)
        {
            return ;
        }
        else
        {
            stack1.push(x);
            cnt++;
        }
    }
    
    int pop() {
        //出栈:
        //(1)空栈
        if(cnt == 0)
        {
            return -1;
        }
        //(2)
        cnt--;  //注意更新cnt 就好
        int top_num = stack1.top();
        stack1.pop(); // 原来忘记出栈
        return top_num;
    }
    
    void increment(int k, int val) {
        //前k个栈底 元素 增加val
        //直接利用 辅助栈 进行操作即可
        stack stack2;
        //case1:cnt<=k , 所有元素增加val
        while(!stack1.empty())
        {
            int tmp = stack1.top();
            stack1.pop();
            stack2.push(tmp);
        }
        int time=1;//总共k个元素即可
        while(!stack2.empty())
        {
            int tmp = stack2.top(); //应该从栈底开始,这就是栈底啊
            stack2.pop();
            //进栈的时候有讲究
            if(time <= k)
            {
                time++;
                stack1.push(tmp+val);
            }
            else{
                stack1.push(tmp);
            }
        }
        //case2: 在进栈的时候进行加即可
    }
};

T14:从 多个栈中 按照顺序取出 k个 硬币的 面值和最大

一张桌子上总共有 n 个硬币  。每个栈有 正整数 个带面值的硬币。

每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里。

给你一个列表 piles ,其中 piles[i] 是一个整数数组,分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k ,请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少 。

解:

扩展,由于需要用到 动态规划的 背包问题的内容这里 进行动态规划那本leetbook / 背包问题的学习

未完待续。。。

你可能感兴趣的:(leetcode,算法,数据结构)