首页 > 其他分享 >链表-栈例题

链表-栈例题

时间:2024-10-08 11:35:37浏览次数:11  
标签:insert include int 链表 括号 ans 例题 表达式

MT2135调整队伍

马蹄集:链表

小码哥迎来了他大学的第一次军训,军训的第一个项目就是列队,每个同学在队伍中都有属于自己的编号。但在练习过程中,教官怎么看这支队伍怎么不顺眼,于是决定调整一下队伍的顺序。

为了顺便考验同学们的反应力,教官与学生们约定了一个口令,每当他说x y 0,x号同学就要移动到y号同学的前面,每当他说x y 1,x号同学就要移动到y*号同学的后面,但学生们不想一次次慢慢移动这么麻烦,想要知道队伍最后是怎么排的然后直接排好。为了解决同学们的烦恼,小码哥立刻动手原地写了一个程序算出了最终排序。

现在告诉你队伍从前到后的初始排序编号以及教官的口令,要你得出队伍从前往后的最终排序。已知有n个学生,编号不重复且1≤编号≤n1≤编号≤n

格式

输入格式:

第一行两个正整数n,m,表示学生的数量和教官口令的数量;
第二行n个正整数,表示学生们的初始排序;
接下来m行,每行3个整数,表示教官的口令。

输出格式:

nn个数字,每个数字之间用空格隔开,表示队伍从前往后的最终排序。

样例 1

输入:

10 5
8 4 6 7 9 3 5 10 1 2 
4 9 0
10 5 1
3 9 0
1 9 1
3 6 0

输出:

8 3 6 7 4 9 1 5 10 2 

AC代码:

#include<iostream>
using namespace std;
//这是一个实现循环链表,操作数字前插尾插的操作代码;
const int ma=3e5+7;
struct add{
    int l; //左节点;
    int r; //右节点;
}insert[ma];
int n,m,ne,head;
int main(){
    cin >> n >> m;
    //初始化,实现把输入的各各节点已链表的形式连接起来;
    while(n--){
        int tt;
        cin >> tt;
        insert[tt].l=ne;
        insert[ne].r=tt;
        ne=tt;
    }
    while(m--){
        int x,y,op;
        cin >> x >> y >> op;
        //记录要操作的左右节点;
        int i=insert[x].l,j=insert[x].r;
        //不管怎样都是要实现删除;
        //在外头就实现删除,让操作的左节点的右指针指向右节点的左指针;
        //在里头就只要实现插入操作;
        insert[i].r=j,insert[j].l=i;
        i=insert[y].l,j=insert[y].r;
        if(op){
            //循环链表基操;
            //操作数后插操作;
            insert[x].l=y;
            insert[x].r=j;
            insert[y].r=x;
            insert[j].l=x;
        }else{
            //操作数前插操作;
            insert[x].l=i;
            insert[x].r=y;
            insert[y].l=x;
            insert[i].r=x;
        }
    }
    //这里刚开始会有点迷;
    //这里主要实现从头(0节点)的右节点开始;
    ne=insert[head].r;
        //直到遇到一个非正数的数值(/n)等等停止;
        while(ne){
            cout << ne << " ";
            ne=insert[ne].r;
            //一直指向下一个右节点;
     }
    return 0;
}

MT2114括号家族

马蹄集:

小码哥在研究只有左括号和右括号组成的序列。给出一个括号序列,求出最长合法子串和它的数量(合法的定义:这个序列中左右括号匹配)。

例如:(()不合法,)()(也不合法,但()()(())合法。

格式

输入格式:

输入一行只有左括号和右括号组成的序列(只包含小括号)。

输出格式:

输出两个数字:最长子字符串的长度,以及此类子字符串的数量,如果没有这样的子字符串,则输出0 1

样例 1

输入:

()()))()()(()

输出:

4 2
备注

其中:字符串长度小于等于 10^6;

AC代码:

#include<iostream>
#include<stack>
#include<map>
using namespace std;
//这算个是栈的最最基础代码(主要是用到的两常用容器,下次在见就是复习了)
const int N=10000010;
//pair<char,int>定义映射两种类型;
stack<pair<char,int>> st;
int arr[N]={0};
int main(){
    string s;
    cin >> s;
    int len=s.size();
    for(int i=0;i<len;i++){
        //左括号操作;
        if(s[i]=='('){
            //映射左括号,以及它的下标;
            pair<char,int> tmp(s[i],i);
            //压入栈中;
            st.push(tmp);
        }else{
            //如果栈中是左括号遇到右括号,标记对应的左右括号为 1;
            //first这里代表char类型的操作;
            if(!st.empty() && st.top().first=='('){
                //st.top(),second:栈头元素的int类型进行操作;
                //这里就让int类型的操作赋值为 1;
                //arr[i]右括号赋值为 1;
                arr[i]=arr[st.top().second]=1;
                //栈顶出栈(左括号);
                st.pop();
            }else{
                //俩都不是就继续压入栈中;
                pair<char,int> tmp(s[i],i);
                st.push(tmp);
            }
        }
    }
    //map老朋友了,这里ans记录长度,mp[ans]计入个数;
    map<int,int> mp;
    int ans=0,ct=0;
    for(int i=0;i<len;i++){
        if(arr[i]==1){
            ct++;
        }else{
            if(ct>=ans){
                ans=ct;
                mp[ans]++;
            }
            ct=0;
        }
    }
    //    在代码中,ct 用于计算当前有效括号的数量,而 ans 用于记录最大有效括号的长度。
    // 当遇到无效括号时,代码会检查当前有效的长度 ct 是否大于等于 ans,如果是,就更新 ans 并重置 ct 为0。
    //    但是,在循环结束后,如果最后有一段有效的括号(例如字符串以有效括号结尾),就要再次检查 ct。
    // 这就是后面的 if(ct >= ans) 这一段的目的,以确保我们不会遗漏最后的有效长度。
    if(ct>=ans){
        ans=ct;
        mp[ans]++;
    }
    if(ans==0) cout << "0 1" << endl;
    else cout << ans << " " << mp[ans] << endl;
    return 0;
}

后缀表达式的值

一本通:

从键盘读入一个后缀表达式(字符串),只含有0-9组成的运算数及加(+)、减(—)、乘(*)、除(/)四种运算符。每个运算数之间用一个空格隔开,不需要判断给你的表达式是否合法。以@作为结束标志。

比如,16–9(4+3)转换成后缀表达式为:16□9□4□3□+–,在字符数组A中的形式为:

栈中的变化情况:

运行结果:-47

提示:输入字符串长度小于250,参与运算的整数及结果之绝对值均在264264范围内,如有除法保证能整除。

【输入】

一个后缀表达式。

【输出】

一个后缀表达式的值。

【输入样例】

16 9 4 3 +*-@

【输出样例】

-47

AC代码:

解法一:数组;

(这个仅供参考)

#include<iostream>
#include<cstring>
using namespace std;
const int Ma=100010;
long long a[Ma];
int con=0;
int main(){
    string s;
    getline(cin,s);
    int n=s.size();
    int x=0;
    for(int i=0;i<n;i++){
        if(s[i]=='+'){
            a[con-2]+=a[con-1];
            con--;
        }else if(s[i]=='-'){
            a[con-2]-=a[con-1];
            con--;
        }else if(s[i]=='*'){
            a[con-2]*=a[con-1];
            con--;
        }else if(s[i]=='/'){
            a[con-2]/=a[con-1];
            con--;
        }else{
            while(i<n && s[i]>='0' && s[i]<='9'){
                x=x*10+s[i]-'0';
                i++;
            }
            a[con++]=x;
            x=0;
        }
    }
    cout << a[0] << endl;
    return 0;
}

解法2:栈操作;

#include<iostream>
#include<stack>
#include<string>
using namespace std;
stack<long long> st;
string s;
int main(){
    getline(cin,s);
    int n=s.length();
    for(int i=0;i<n-1;i++){
        if(s[i]>='0' && s[i]<='9'){
            long long x=0;
            while(s[i]>='0' && s[i]<='9'){
                x=x*10+s[i]-'0';
                i++;
            }
            st.push(x);
        }
        if(s[i]=='+' || s[i]=='-' || s[i]=='*' || s[i]=='/'){
            long long k,l;
            k=st.top();
            st.pop();
            l=st.top();
            st.pop();
            if(s[i]=='+') st.push(l+k);
            if(s[i]=='-') st.push(l-k);
            if(s[i]=='*') st.push(l*k);
            if(s[i]=='/') st.push(l/k);
        }
    }
    cout << st.top() << endl;
    return 0;
}

中缀表达式值(expr)

一本通:栈

​ 输入一个中缀表达式(由0-9组成的运算数、加+减-乘*除/四种运算符、左右小括号组成。注意“-”也可作为负数的标志,表达式以“@”作为结束符),判断表达式是否合法,如果不合法,请输出“NO”;否则请把表达式转换成后缀形式,再求出后缀表达式的值并输出。

注意:必须用栈操作,不能直接输出表达式的值。

【输入】

一行为一个以@结束的字符串。

【输出】

如果表达式不合法,请输出“NO”,要求大写。

如果表达式合法,请输出计算结果。

【输入样例】

1+2*8-9@

【输出样例】

8

AC代码:

#include <iostream>
#include <stack>
#include<string>
using namespace std;
const int Ma=100010;
//创建一个结构体:存储后缀表达式运算符和操作数
struct Node{
    int n;    //数值
    char c;    //运算符
}eq[Ma];

string s;
int p;      // 后缀表达式的索引
int pri[128]; // pri[i]: ascii码为i的运算符的优先级

//运算符优先级:
void initpri(){
    pri['(']= 4;
    pri['*']=pri['/']= 3;
    pri['+']=pri['-']= 2;
    pri[')']= 1;
}

// 计算给定的两个数字和运算符的结果
int calc(int a, int b, char c) 
{
	switch(c)
	{
		case '+':
			return a + b; // 加法
		case '-':
			return a - b; // 减法
		case '*':
			return a * b; // 乘法
		case '/':
			return a / b; // 除法
	}	
}



bool Chva(char c){
    return c=='+' || c=='-' || c=='*' || c=='/' || c=='(' || c==')';
}

bool legal(){
    stack<char> st;
    for(int i=0;i<s.length();i++){
        //判断匹配问题;
        if(s[i]=='('){
            st.push(s[i]);
        }else if(s[i]==')'){
            if(st.empty()){
                return false;     //在栈为空的情况下,单进右括号???
            }else{
                st.pop();        //栈不空,出栈;
            }
        }
    }
    if(!st.empty()) return false;            //栈不为空的情况下,还有括号???

    //判断‘-’当负号处理;
    for(int i=0;i<s.length();i++){
        //细节:如果第一位是负号,则将其变为‘0’+‘-’,到时候在数字操作中就变成了 0-x, 0-任何正数都得-数;
        if(i==0 && s[i]=='-'){
            s='0'+s;
        }else if(s[i]=='-' && s[i-1]=='('){       //这里就是(-2+3)这种情况,在‘-’前面插入一个‘0’;
            s.insert(i,"0");                      //为什么不考虑-(2+3)这种情况?出现这种情况是只会出现在头
        }                                         //在中途的话是当减号处理的;

        //判断算式头尾问题;(要知道正常的算式头和尾都是数字,或者左右括号,唯一的负号开头,已经在上添加了‘0’开头)
        if(Chva(s[0]) && s[0]!='('){   //头
            return false;
        }
        int len=s.length()-1;          //尾
        if(Chva(s[len]) && s[len]!=')'){
            return false;
        }
    }

    for(int i=0;i<s.length();i++){
        if(Chva(s[i]) && Chva(s[i+1])){
            if(s[i]==')' && s[i+1]=='('){
                return false;
            }else if(!(s[i]==')' || s[i+1]=='(')){   //细节:如果两个字符都能匹配的只有左边是‘)’ ,右边是‘(’ ;
                return false;                       //打个比方:s[i]=='+',就继续判断s[i+1]=='('; 1+(2+2);
            }                                       //s[i]==')',s[i+1]=='+'; (1+2)+3;
        }
    }
    return true;             //上述都不满足,就输出true;
}

// 递归求解后缀表达式 
int Postfix() 
{
    int i = p--; // 从后缀表达式中取出当前操作数或运算符的索引
    if(eq[i].c) // 如果当前是运算符
    {
        int b = Postfix(); // 递归求解第二个操作数
        int a = Postfix(); // 递归求解第一个操作数
        return calc(a, b, eq[i].c); // 返回计算结果
    }
    else{
        return eq[i].n; // 如果是数字,直接返回
    }
}

int main(){
    //初始化优先级表;
    initpri();

    cin >> s;

    //首先判断表达式是否合法;
    if(legal()==false){
        cout << "NO" << endl;
        return 0;
    }

    //创建栈;
    stack<char> cSta;

    bool flag=false;
    int ans=0;
    //直接转后缀表达式,如果不是合理表达式,直接输出no,在转后缀表达式,判断如果是合法,求出结果;这到不如直接合并解决;
    //将中缀表达式转换为后缀表达式;
    for(int i=0;i<s.size();i++){
        if(s[i]>='0' && s[i]<='9'){
            flag=true;
            ans=ans*10+s[i]-'0';
        }else {
            if(flag){
            eq[++p].n=ans;
            flag=false;
            ans=0;
            }
            //这个!() 刚开始一直没理解什么意思; 
            //现在解释:先判断括号里的条件,从cSta开始判断,以此不满足就 || ;(get这句话)
            //括号里判断成功说明,条件true,在到括号外取反跳出循环;(get这句话)
            //get到上两句的话:就方便实现,最后一个cSta.top()是'('问题;左右括号其实就是判断条件,并不入栈;
            while(!(cSta.empty() || pri[s[i]]>pri[cSta.top()] || cSta.top()=='(')){
                eq[++p].c=cSta.top();
                cSta.pop();
            }
            //结合上面:手推算式就知道这个判断括号问题了;
            if(!cSta.empty() && cSta.top()=='(' && s[i]==')'){
                cSta.pop();
            }else{
                cSta.push(s[i]);
            }
        }
    }
    cout << Postfix() << endl;
    return 0;
}

标签:insert,include,int,链表,括号,ans,例题,表达式
From: https://www.cnblogs.com/mznq/p/18451341

相关文章

  • 707_设计链表
    707_设计链表【问题描述】你可以选择使用单链表或者双链表,设计并实现自己的链表。单链表中的节点应该具备两个属性:val和next。val是当前节点的值,next是指向下一个节点的指针/引用。如果是双向链表,则还需要属性prev以指示链表中的上一个节点。假设链表中的所有节点下标......
  • 代码随想录算法训练营day4|● 24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个
    学习资料:https://programmercarl.com/0024.两两交换链表中的节点.html学习记录:24.两两交换链表中的节点(添加虚拟头节点;交换1、2节点和3、4节点时,要用1前面的cur,先保存1为temp且3保存为temp1,cur指向2,再把2指向temp,因为cur指向2后就与1没关联了)点击查看代码#Definitionforsi......
  • 代码随想录算法训练营day3|● 203.移除链表元素 ● 707.设计链表 ● 206.反转链表
    学习资料:https://programmercarl.com/链表理论基础.html#链表的类型可设置虚拟头结点dummy_head链表最后指向Null一个节点包含值和索引学习记录:203.移除链表元素(基本ListNode(),cur.next,cur.next.val)点击查看代码#Definitionforsingly-linkedlist.#classListNod......
  • [leetcode 25]. K 个一组翻转链表
    题目描述:https://leetcode.cn/problems/reverse-nodes-in-k-group给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯......
  • [leetcode 92] 反转链表 II
    题目描述:https://leetcode.cn/problems/reverse-linked-list-ii给你单链表的头指针 head 和两个整数 left 和 right ,其中 left<=right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。 示例1:输入:head=[1,2,3,4,5],left=2,right......
  • leetcode24 两两交换链表中的节点(swap-nodes-in-pairs)
    题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。示例1:输入:head=[1,2,3,4]输出:[2,1,4,3]示例2:输入:head=[]输出:[]示例3:输入:head=[1]输出:[1] 提示:链表中节点的数......
  • linux内核双向链表使用list klist
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、list和klist是什么?二、代码示例1.list2.klist总结前言提示:这里可以添加本文要记录的大概内容:linux内核中大量使用了链表数据结构来存储各种数据,比如device和driver使用klist存储,下......
  • 【LeetCode Hot 100】23. 合并K个升序链表
    题目描述看到这个题目会想起之前做过的合并2个升序链表。在那个题目中,由于两个链表都已经是升序的,可以将两个链表的元素进行逐个比较并添加到答案链表中。但是在本题中,每次循环都需要在k个链表的当前元素中找出最小的,而且需要在所有k个链表都遍历完之后跳出循环,所以效率比较低。......
  • 数据结构~~链表
    目录一、链表的概念二、单链表1.单链表的结构2.单链表的接口实现 2.1、动态申请节点2.2、单链表打印 2.3、摧毁单链表 2.4、单链表尾插 2.5、单链表的头插 2.6、单链表的尾删 2.7、单链表的头删 2.8、单链表在pos位置之前插入x2.9、单链表删除pos位置的值......
  • 信息学奥赛复赛复习07-CSP-J2020-03表达式前置知识点-结构体、链表、链式前向星
    PDF文档公众号回复关键字:2024093012020CSP-J题目1优秀的拆分[题目描述]链式前向星模板题,读入n个点,m条边,以及flag,若flag==1则图有向,否则无向。对每个点输出它的每一条边[输入格式]第一行三个数n,m,flag,题意如上所示第2~1+m行,每行三个数,x,y,z,代表从x到y有一条长为z的......