算法学习之路的心得四之数据结构

GDUT 20 寒假集训专题4.数据结构

  1. 总结
  2. 题目题解

1.栈

​ 栈又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

基本调用代码

#include <stack>   //头文件
using namespace std;
stack < int >  S  ;  //< >里面是栈存的数据的类型,这样就可以定义一个叫S的存整型的栈
//常用功能
S.size() ; //返回栈的元素数
S.top()	;  //返回栈顶的元素
S.pop()	;  //从栈中取出并删除元素
S.push(x); //向栈中添加元素x
S.empty(); //在栈为空时返回true

2.队列

​ 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

基本调用代码

#include <queue>   //头文件
using namespace std;
queue < int >  Q  ;  //< >里面是队列存的数据的类型,这样就可以定义一个叫Q的存整型的队列
//常用功能
Q.size() ; //返回队列的元素数
Q.front();	  //返回队头的元素
Q.pop()	 ; //从队列中取出并删除元素
Q.push(x) ;//向队列中添加元素x
Q.empty(); //在队列为空时返回true

3.动态数组

动态数组是指在声明时没有确定数组大小的数组,即忽略圆括号中的下标,使用动态数组的优点是可以根据用户需要,有效利用存储空间。

基本调用代码

#include <vector>
using namespace std;
vector <int > V;
V.size (); //返回向量的元素数
V.push_ back (x) ;//在向量末尾添加元素X
V.Pop_ back();  //删除向量的最后一-个元素
V.begin(); //返回指向向量开头的迭代器
V.end(); //返回指向向量末尾( 最后一个元素的后一个位置)的迭代器

4.链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

常用的代码

#include <list>
using namespace std;
list <int > L;
L.size ();  //返回表的元素数
L.begin();  //返回指向表开头的迭代器
L.end() ; //返回指向表末尾(最后一个元素的后一个位置)的迭代器
L.push_ front (x) ; //在表的开头添加元素x
L.push_ back (x) ;//在表的末尾添加元素x
L.pop_ front () ;//删除位于表开头的元素
L.pop_ back () ;//删除位于表末尾的元素
L.insert(p, x) ;//在表的位置p处插入元素x
L.erase (p) ;//删除表中位置p的元素
L.clear () ;//删除表中所有元素

1.括号匹配问题

题目链接

题目描述: 在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$“标注,不能匹配的右括号用”?"标注.

解题思路:考虑用栈来解决这个问题,遇到左括号就把左括号压栈,遇到右括号就查看栈里面是否有左括号,如果没有,那显然这个右括号是非法的,如果有,那就把栈顶的左括号pop出来。要注意一点就是最后要检查栈里面是否还有左括号,如果整个字符串都遍历完了,但是栈里面还留有一些左括号,那么显然这些左括号也是非法的,所以压栈的时候要记录一下压进去的左括号的位置,或者直接把位置压进去应该也是可行的,(但是我没这么做qwq)。

ac代码

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <stack>
using namespace std;
struct node {
	char ch;
	int s;
}N;
int main()
{
		string a;
		char ans[105];
		stack <node > S;
		while(cin>>a){
			for(int i=0;i<=104;i++){
				ans[i]=' ';
			}
			for(int i=0;i<a.size() ;i++){
				if(a[i]=='('){
					N.ch='(';
					N.s=i;
					S.push(N); 
				}
				else if(a[i]==')'){
					if(S.empty()){
						ans[i]='?';
					}
					else
					S.pop() ;
				}
			}
			while(!S.empty()){
				
				N=S.top() ;
				S.pop() ;
				ans[N.s]='$';
			}
			
			cout<<a<<'\n';
			for(int i=0;i<a.size() ;i++){
				cout<<ans[i];
			}
			cout<<'\n';
		}
		return 0;
}

2.Smallest Substring

题目链接

题目描述:

给定一个字符串S和一个整数K,你的任务是找到满足以下条件的字典上最小的字符串T:

  1. T是S的子序列

  2. T的长度是K。

解题思路:这里我是用链表做的,题目其实很明确,找最小字典序嘛…我的理解是,可以转换成找区间的最小值,大概就是,前n个数中找一个最小值,那第n个位置的最小字典序就是那个最小值(画图举例脑补一下下qwq),但是有一个问题,如果我这样做的话,那复杂度就是O(n²),那显然会超时,所以我用了其他方法,就是先用链表把n个数存下来,然后从第一个开始遍历,如果一个数比它后面那个数小的话,那就把这个数删了, 这里就发挥了链表的优越性了,如果用数组来存这些数,删起来会比较麻烦。一直删,直到n等于k为止那么留下来的k个数就是满足题意得最小字典序啦。

ac代码

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <stack>
#include <queue>
#include <list>
using namespace std;

int main()
{
		list <char > L;
		int k,n;
		string a;
		cin>>k;
		cin>>a;
		n=a.size() ;
		for(int i=0;i<n;i++){
			L.push_back(a[i]);
		}
		list <char >::iterator itn=L.begin();
		list <char >::iterator it=L.begin();
		while(n>k){
			it++;
			if(it==L.end()){
				break;
			}
			if(*itn>*it){
				L.erase(itn);
				if(it!=L.begin()){
					it--;
				}
				n--;
			}
			
			itn=it;
		}
		it=L.begin();
		int i=0;
		for(it;i<k;i++,it++){
			cout<<*it;
		}
		return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值