1.30C语言学习

P2758 编辑距离

一道关于字符串的动态规划的题目,总的来说就是不会写,看题解也看了很久,这个思路也是自己完全想不到的

假设用f[i][j]表示将串a[1…i]转换为串b[1…j]所需的最少操作次数(最短距离)

首先是边界:

①i==0时,即a为空,那么对应的f[0][j]的值就为j:增加j个字符,使a转化为b

②j==0时,即b为空,那么对应的f[i][0]的值就为i:减少i个字符,使a转化为b

然后考虑一般情况(这里是DP思想):我们要得到将a[1..i]经过最少次数的操作就转化为b[1..j],那么我们就必须在此之前以最少次数(假设为k次)的操作,使现在的a和b只需再做一次操作或者不做操作就可以使a[1..i]转化到b[1..j]。而“之前”有三种情况:

①将a[1…i]转化为b[1…j-1]

②将a[1..i-1]转化为b[1..j]

③将a[1…i-1]转化为b[1…j-1]

第①种情况,只需要在最后将a[j]加上b[1..i]就可以了,总共就需要k+1次操作。

第②种情况,只需要在最后将a[i]删除,总共需要k+1个操作。

第③种情况,只需要在最后将a[i]替换为b[j],总共需要k+1个操作。但如果a[i]刚好等于b[j],就不用再替换了,那就只需要k个操作。

为了得到最小值,将以上三种情况的最小值作为f[i][j]的值(我前面不是说了f[i][j]表示串a[1…i]转换为串b[1…j]所需的最少操作次数),最后答案在f[n][m]中。

#include<bits/stdc++.h>
using namespace std;
char a[3009],b[3009];
int f[3009][3009],lena,lenb;
int main(){
	scanf("%s %s",a+1,b+1);
	lena=strlen(a+1);
	lenb=strlen(b+1);
	for(int i=1;i<=lena;i++){
		for(int j=1;j<=lenb;j++){
			f[i][0]=i,f[0][j]=j;
			if(a[i]==b[j])f[i][j]=f[i-1][j-1];
			else f[i][j]=min(f[i-1][j],min(f[i][j-1],f[i-1][j-1]))+1;
		}
	}
	printf("%d",f[lena][lenb]);
	return 0;
}

数嘛),最后答案在f[n][m]中。

实现(只描述算法部分)

初始化。边界情况,用循环嵌套或两个独立的循环都可以做到。

2.循环嵌套遍历f数组,先处理a[i]==b[j]的情况,如不满足,再从三种情况中选择最小的,作为f[i][j]的值。三种情况中,①如果在k个操作里将a[1…i-1]转换为b[1..j],那就可以将a[i]删除,共需k+1个操作,所以是f[i-1][j]+1;②如果在k个操作里将a[1…i]转换为b[1…j-1] ,那就可以加上b[j],共需k+1个操作;③如果我们可以在k个操作里将a[1…i-1]转换为b[1…j-1],那就可以将a[i]转换为b[j],也是共需k+1个操作。(前面已经处理过了a[i]==b[j]的情况)

3.最后的答案是f[][]最后一个元素的值。

P4913 【深基16.例3】二叉树深度

每个节点有两个子节点,用结构体定义左边节点和右边节点,用dfs对每个节点进行遍历搜索

这道题要我们求二叉树的深度,就一定要遍历这棵树。

首先明确一点题目中未提到的,编号为11的节点是二叉树的根节点。

于是我们可以从根节点出发,先递归遍历该节点的左节点,再递归遍历该节点的右节点。

其中还要记录该节点的深度,出发时深度为11

dfs(tree[id].left, deep+1);
dfs(tree[id].right, deep+1);

每到一个节点时更新一下深度:

ans = max(ans, deep);

到达叶子节点时,就return

if (id == 0) return ;

总体上就这么多吧。

因为每个节点遍历一次,代码如下

#include<bits/stdc++.h>
using namespace std;
struct node{
	int left;
	int right;
};
node tree[1000005];
int deeps=-1;
void dfs(int now,int deep){
	if(now==0)return;
	deeps=max(deeps,deep);
	dfs(tree[now].left,deep+1);
	dfs(tree[now].right,deep+1);
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d",&tree[i].left,&tree[i].right);
	}
	dfs(1,1);
	printf("%d",deeps);
	return 0;
}

P4715 【深基16.例1】淘汰赛

是在二叉树题单里找到的题,看了题目之后知道二叉树的解法大概是什么样式的,但是自己根本无法实现那段代码,看了题解发现实在是太冗长了索性就放弃吧,看到下一篇题解是个stl容器queue的方法,我还没往下看我就有思路了,只怪自己被题单的标题限制了思维,这里还用到了stl容器pair,键值对,用为不确定能力值会不会有相等的情况,所以没有用map,下面是ac代码,每次取从队头两个出来比较,将胜者放进队尾,限定queue的元素数量,最后在进行一次比较就能出答案

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	scanf("%d",&n);
	int nn=1<<n;
	queue<pair<int,int>>que;
	int x;
	for(int i=1;i<=nn;i++){
		scanf("%d",&x);
		que.push(make_pair(i,x));
	}
	while(que.size()>2){
		pair<int,int>x,y;
		x=que.front();
		que.pop();
		y=que.front();
		que.pop();
		if(x.second>y.second)que.push(x);
		else que.push(y);
	}
	pair<int,int>a,b;
	a=que.front();
	que.pop();
	b=que.front();
	que.pop();
	if(a.second>b.second)printf("%d",b.first);
	else printf("%d",a.first);
	return 0;
}

关于pair

当想要将两个元素绑在一起作为一个合成元素,又不想因此定义结构体时,使用pair可以很方便地作为一个替代品。pair实际上可以看作一个内部有两个元素的结构体,且这两个元素的类型可以指定。

添加头文件和参数
#include<utility>
//或
#include<map>  
using namespace std;

pair()两个参数:分别对应first和second的数据类型,可以是任意基本数据类型或容器

定义pair():
pair<typename1,typename2> name;
//例如:
pair<string,int> p;
定义并初始化:
pair<string,int> p("haha",5);
使用pair对map键值进行插入
mp.insert(make_pair("heihei",5));
//或
mp.insert(pair<string,int>("heihei",5));
使用pair中的元素
#include<utility>
#include<iostream>
using namespace std;
int main()
{
    pair<string,string>s1;
    s1.first="ctx";
    s1.second="666";
    cout<<s1.first<<endl;
    cout<<s1.second<<endl;
    cout<<s1.first<<s1.second<<endl;
}

二叉树的了解和学习

首先,什么是树型结构?

树形结构中的数据元素之间存在一种一对多的层次关系

树型结构反映了数据元素之间的层次关系和分支关系,非常类似于自然界中的树。树型结构在现实生活中广泛存在,如企业的组织结构图等。另外,在计算机科学中亦具有广泛的应用,如编译程序中源程序的语法结构就是用树型结构来表示的;数据库系统中也采用树型结构组织信息。

对于树的定义还需要强调两点:

1. 根结点是唯一的,不可能存在多个根结点,别和现实中的大树混在一起,现实中的树有很多根须,那是真实的树,数据结构中的树是只能有一一个根结点。
2. 子树的个数没有限制,但它们一定是互不相交的。

 需要重点记住:树形结构中,子树之间不能有交集,否则就不是树形结构

下面我们正式来介绍二叉树

 二叉树( Binary Tree)是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。

通常对于在某个阶段都是两种结果的情形,比如开和关、0和1、真和假、上和下、对与错,正面与反面等,都适合用树状结构来建模,而这种树是一种很特殊的树状结构,叫做二叉树。

一棵二叉树是结点的一个有限集合,该集合
1. 或者为空
2. 或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

特殊二叉树 
 我们再来介绍一些特殊的二叉树。这些树可能暂时你不能理解它有什么用处,但先了解一下,以后会提到它们的实际用途。

1.斜树

顾名思义,斜树一定要是斜的,但是往哪斜还是有讲究。所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树。斜树有很明显的特点,就是每一层都只有一个结点,结点的个数与二叉树的深度相同。

2.满二叉树

在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是2的K次方减一 ,则它就是满二叉树

单是每个结点都存在左右子树,不能算是满二叉树,还必须要所有的叶子都在同
一层上,这就做到了整棵树的平衡。因此,满二叉树的特点有:
(1)叶子只能出现在最下一-层。出现在其他层就不可能达成平衡。
(2)非叶子结点的度- -定是2。否则就是“缺胳膊少腿”了。
(3)在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。

3.完全二叉树

完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

注意了,满二叉树一定是完全二叉树

二叉树的存储
  对于二叉树的存储,由于树是一种一对多的关系结构。所以顺序存储实现树是比较困难的,但是二叉树是一种特殊的树,由于它的特殊性,使得用顺序存储结构也可以实现,但目前我们先不对顺序存储实现二叉树做过多的叙述,因为对于二叉树的存储,顺序存储的适用性并不强,用的最多的往往是链式存储结构,下面我们就来介绍二叉树的链式存储(二叉链表)

 叉树每个结点最多有两个孩子,所以为它设计-一个数据域和两个指针域是比较自然的想法,我们称这样的链表叫做二叉链表。

// 孩子表示法
struct Node {
  int val; // 数据域
  Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
  Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
} 
 
// 孩子双亲表示法
struct Node {
  int val; // 数据域
  Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
  Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
  Node parent; // 当前节点的根节点
}
二叉树的三种遍历方式

1.先序遍历
若二叉树为空,则空操作;否则:
(1)访问根结点
(2)先序遍历左子树
(3)先序遍历右子树

2.中序遍历
若二叉树为空,则空操作;否则:
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树

3.后序遍历
若二叉树为空,则空操作;否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点

  • 12
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值