【基础算法训练】—— 栈

简介: 【基础算法训练】—— 栈

第一题 P4702 取石子


题目描述

微信图片_20221019211857.png解题报告


原本以为会使很复杂的题目,比如去思考各自怎么取才能保证最优了,其实这些想法都是不必要的,因为题目已经说,两个人都很聪明,都是采用的最优取法,那么此时,题目的前提是Alice先手,而且最后一定会把石子拿完。


倘若Alice想赢,最后一次必须她来取,也就是石子的总数要是奇数;

因为Bob是第二个拿,倘若想要Bob赢,那么就石子的总数就必须是偶数,在偶数的情况下,Bob拿了石子之后,可以直接再让Alice拿不到石头。

这两个人太坏了


参考代码(C++版本)

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
int main()
{
  int n;
  cin >> n;
  int sum = 0;
  //统计每一堆石子的个数
  for(int i = 0; i < n;i++) 
  {
    int m;
    cin >> m;
    sum += m;
  }
  if(sum%2) puts("Alice");
  else puts("Bob");
  return 0;
}

第二题 P5638 【CSGRound2】光骓者的荣耀


题目描述


微信图片_20221019212221.png

解题报告


第一次读题可能会感觉像是图的题,但是看到下面的样例演示,应该可以感觉到,其实是让统计某个区间中花费的时间,数据范围是1 0 6 10^610 6,直接暴力是会超时的。求区间和?前缀和算法就可以拿出来了。

微信图片_20221019212312.png

参考代码(C++版本)

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
const int N = 1e6+10;
LL sum[N];
int main()
{
  //前缀和
  int n , k;
  cin >> n >>k;
  //可以从1号点直达n号点,其间的半径为n-1
  if(k >= n-1) cout << 0;
  //预处理前缀和
  for(int i = 1; i < n;i++)
  {
    LL x = 0;
    cin >>x;
    sum[i] = sum[i-1] + x;
  }
  LL ans = sum[n-1];//这个ans记录的是当前最大的前缀和
  //再使用传送机k来跳跃,找到最小的
  for(int i = k; i < n;i++)
    ans = min(ans,sum[n-1]-(sum[i]-sum[i-k]));
  cout << ans;
  return 0;
}

第三题 1441. 用栈操作构建数组


题目描述


微信图片_20221019212421.png

解题报告


题目的背景蛮简单的,是相当于给咱一个序列,然后让咱们用栈的出栈和入栈的思想,去实现目标数组的状态。

因为序列和目标数组都是严格升序排列的,那么我们只需要从1开始,逐渐将1到n的数字转移Push进去,倘若在遍历的过程中,遇到目标数组不想要的,就使用Pop弹出。


参考代码(C++版本)

class Solution {
public:
    vector<string> buildArray(vector<int>& target, int n) {
        //题目意思是给我们一个1~n的数组,然后嘞,咱们用栈的思想去构建模板数组
        vector<string> ans;
        int len = target.size();
        //扫一遍,根据情况push 和 pop
        for(int i = 1,j = 0;i <= n;i++)
        {
            //凑成目标数组了
            if(j == len) return ans;
            //遇到数字直接先压进去
            ans.push_back("Push");
            //倘若不是模板数组中想要的了,再弹出来。
            if(i != target[j]) ans.push_back("Pop");
            else j++;
        }
        return ans;
    }
};


第四题 1021. 删除最外层的括号


题目描述


image.png

解题报告


这个题目,难度可能不大,但是读题挺费解的,题目的意思其实是让我们拆出一对()中包含的括号。

倘若使用栈来维护,那么我们需要在统计的一对()之间的内容。

因此,我们在栈为空,并且当前的字符是(的时候,标记该字符的下一个位置,即l = i + 1。

当遇到的字符是)的时候,就以为着出现一对()括号了,此时就得开始清楚这个括号()里的内容了,假如经过pop之后,栈变成空的了,那么就是当前这个()区间的信息统计完成了,标记当前位置,即r = i。

最后使用substr截取出这个区间中字符串信息。


参考代码(C++版本)

class Solution {
public:
    string removeOuterParentheses(string s) {
        //栈结合双指针来玩
        int l = 0,r= 0;//代表截取区间的左指针和右指针
        int n = s.size();
        stack<char> stk;
        string ans = "";
        for(int i = 0; i < n;i++)
        {
            //如果当前遇到的是左括号
            if(s[i] == '(')
            {
                //而且当前这个栈是空的,标记截取区间的左端点
                if(stk.empty()) l = i+1;
                //否则不标记,常规的入栈
                stk.push(s[i]);
            }
            //如果当前的栈不是空的,而且当前遇到右括号了,弹出栈顶的东西
            if(!stk.empty() && s[i] == ')') stk.pop();
            //经过出栈操作之后,栈空
            if(stk.empty())
            {
                r = i;
                //s.substr(pos, n) 截取s中从pos开始(包括0)的n个字符的子串,并返回
                ans += s.substr(l,r-l);
            }
        }
        return ans;
    }
};

第五题 1700. 无法吃午餐的学生数量


题目描述


微信图片_20221019212852.png

解题报告


本题的逻辑了,仍是常规的模拟吧。

因为三明治只有被取,那么相当于栈的出栈,所以就用栈来维护了。

学生排队取三明治了,有拿到满意的了,顺利出队不再回来,也有暂时拿不到满意的,出队之后又入队,所以可以使用一个队列来维护了。


题目给咱的是两个数组,这就需要咱们把数据取出来分别放到栈和队列中的。至于模拟取三明治的过程了,可以使用学生队列的长度用于循环,当有学生拿到自己满意的了,就将循环变量重置置为0,重新循环。

那么,倘若整个队列循环结束了,仍是匹配不到适合的三明治的时候,就结束循环,返回结果,确实是吃不到了。


参考代码(C++版本)

class Solution {
public:
    int countStudents(vector<int>& students, vector<int>& sandwiches) {
        //用栈记录三明治,三明治只有出栈
        //用队列记录学生,学生有出队和入队
        stack<int> stk;
        queue<int> q;
        int sand_len = sandwiches.size();
        int stu_len = students.size();
        //把三明治的信息倒着存入栈中
        for(int i = sand_len-1; i >= 0;i--)
            stk.push(sandwiches[i]);
        //把学生的信息顺着存到队列中
        for(int i = 0; i < stu_len;i++)
            q.push(students[i]);
        //把学生作为循环
        for(int i = 0; i < q.size();i++)
        {
            //如果栈顶和队列首相同,就是代表爱吃,那么就出栈,出队
            if(stk.top() == q.front())
            {
                stk.pop();
                q.pop();
                i = -1;//重置循环为i = 0,进行新的一轮(因为待会会有i++)
            }else
            {
                //如果不相同,就是出队,入队
                int tmp = q.front();
                q.pop();
                q.push(tmp);
            }
        }
        //最后队列的长度,就是是在满足不了的。
        return q.size();
    }
};

第六题 1381. 设计一个支持增量操作的栈


题目描述


微信图片_20221019213012.png

解题报告


本质上是用咱们熟悉的数组,手动去模拟栈的实现,算是基础知识了吧,注意细节吧~


参考代码(C++版本)

class CustomStack {
public:
    //这个题,其实就是让咱们数组模拟栈的功能了,基础的数据结构的知识了
    vector<int> stk;
    int top;
    CustomStack(int maxSize) {
        //使用vecotr的resize方法改变Vector元素数量的大小
        stk.resize(maxSize);
        top = -1;
    }
    void push(int x) {
        //先要判断当前的栈有没有满,不满才可以操作
        if(top != stk.size()-1)
        {
            stk[++top] = x;
        }
    }
    int pop() {
        //还是判断可不可以出栈
        if(top == -1) return -1;
        else return stk[top--];
    }
    void increment(int k, int val) {
        //栈底的 k 个元素的值都增加
        int n = min(k,top+1);
        for(int i = 0; i < n;i++)
            stk[i] += val;
    }
};
/**
 * Your CustomStack object will be instantiated and called as such:
 * CustomStack* obj = new CustomStack(maxSize);
 * obj->push(x);
 * int param_2 = obj->pop();
 * obj->increment(k,val);
 */

总结


① 无论是链表还是栈,其实都是可以使用数组模拟出来的,虽然有了STL大法,但是还是不能忘记可爱的数组

② 今天的简单博弈论了,先浅记录一下,不要去管它们怎么拿,只关心谁先手,谁想赢应该怎么办。


相关文章
|
6天前
|
算法 前端开发 vr&ar
☆打卡算法☆LeetCode 225. 用队列实现栈 算法解析
☆打卡算法☆LeetCode 225. 用队列实现栈 算法解析
|
6天前
|
机器学习/深度学习 算法 TensorFlow
文本分类识别Python+卷积神经网络算法+TensorFlow模型训练+Django可视化界面
文本分类识别Python+卷积神经网络算法+TensorFlow模型训练+Django可视化界面
75 0
文本分类识别Python+卷积神经网络算法+TensorFlow模型训练+Django可视化界面
|
1天前
|
缓存 算法 C语言
数据结构与算法⑧(第三章_上)栈的概念和实现(力扣:20. 有效的括号)
数据结构与算法⑧(第三章_上)栈的概念和实现(力扣:20. 有效的括号)
4 0
|
6天前
|
存储 算法
数据结构与算法 栈与队列
数据结构与算法 栈与队列
12 0
数据结构与算法 栈与队列
|
6天前
|
机器学习/深度学习 自然语言处理 算法
【大模型】关于减轻 LLM 训练数据和算法中偏差的研究
【5月更文挑战第6天】【大模型】关于减轻 LLM 训练数据和算法中偏差的研究
|
6天前
|
机器学习/深度学习 数据采集 算法
|
6天前
|
存储 缓存 算法
【算法与数据结构】栈的实现详解
【算法与数据结构】栈的实现详解
|
6天前
|
存储 算法 编译器
【数据结构】栈算法(算法原理+源码)
【数据结构】栈算法(算法原理+源码)
【数据结构】栈算法(算法原理+源码)
|
6天前
|
存储 算法 C语言
数据结构与算法:栈
朋友们大家好啊,在链表的讲解过后,我们本节内容来介绍一个特殊的线性表:栈,在讲解后也会以例题来加深对本节内容的理解
|
6天前
|
消息中间件 算法 调度
数据结构与算法——单向循环列表、栈和队列(附代码)
数据结构与算法——单向循环列表、栈和队列(附代码)
16 2