今天主要是熟悉了并查集的
# 遍历问题
## 题目描述
我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:
所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。
## 输入格式
输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。
## 输出格式
输出可能的中序遍历序列的总数,结果不超过长整型数。
## 样例 #1
### 样例输入 #1
abc
cba
### 样例输出 #1
4
这个题看似简单,实则就是明白前序遍历和后序遍历的特点,当我们清楚后,这个题就变为了找点题,
这个是我的草稿,分别是一个父节点缺少左节点和右节点是前中后遍历的区别,
我们对比发现,缺少左右节点当中一个时,也就是2和3情况时,虽然先序和后序相同但是中序遍历不同
然后我们单独来看这2和3(看作为较上面这个图),和4的对比,当缺少一个节点时,我们可以发现,无论时缺少左还是右,都不会对整个二叉树的前后顺序发生变化,,但是没有缺少左右节点的时候,先序遍历前面的连个与后序遍历最后的两个不相同,
最终,也就代表着,缺少一个节点时,中序遍历不是固定的,有两种去情况,没有缺少节点时,中序遍历的情况的固定的
最后,这个题就变为了寻找有多少的子树问题
#include<bits/stdc++.h>
using namespace std;
int main()
{ long long ans=0;
string s1,s2;
cin>>s1>>s2;
for(int i=0;i<s1.length();i++)
{
for(int j=1;j<s2.length();j++)
if(s1[i]==s2[j]&&s1[i+1]==s2[j-1])
ans++;
}
printf("%lld",1<<ans);
}
并查集:一种树型结构,用于处理一些不相交集合的合并与查询问题。
需要以下三种操作:
(1)建立集合
(2)查找某个元素是否在一给定集合内(或者查找一个元素所在的集合)
(3)合并两个集合
并查集可以使用数组和链表来实现,最常见的是数组的实现
我认为,也就是不断的向上去寻找两个节点的父节点,然后进行对比,父节点不相同我们就更新父节点,注意:我们是将左边的看作是更大的父节点,也就代表着偏向右边的看作是偏向左边的子节点,将右边的更新成左边的。
1.建立集合,初始化
void init()
{
for(int i=1;i<=n;i++)
father[i]=i;
}
2.合并集合&查找元素所属的集合
(1)非递归写法
int find(int x)
{
while(father[x]!=x)
x=father[x];
return x;
}
(2)递归写法:主要是这种
int find(int x)
{
if(father[x]!=x)
return find(father[x]);
else
return x;
}
总体代码
#include<bits/stdc++.h>
using namespace std;
int arr[1001],n,m,sum=0;
void init()
{
for(int i=1;i<=n;i++)
arr[i]=i;
return ;
}
int getf(int v)
{
if(arr[v]==v)
return v;
else
{
arr[v]=getf(arr[v]);
return arr[v];
}
}
void merge(int x,int y)
{
int t1=getf(x);
int t2=getf(y);
if(t1!=t2)
arr[t2]=t1;
return ;
}
int main()
{
int x,y;
cin>>n>>m;
init();
for(int i=1;i<=m;i++)
{
cin>>x>>y;
merge(x,y);
}
for(int i=1;i<=n;i++)
if(arr[i]==i)
sum++;
cout<<sum;
return 0;
}
# 【模板】并查集
## 题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
## 输入格式
第一行包含两个整数 N,M ,表示共有 N 个元素和 M 个操作。
接下来 M 行,每行包含三个整数 Z_i,X_i,Y_i 。
当 Z_i=1 时,将 X_i 与 Y_i所在的集合合并。
当 Z_i=2 时,输出 X_i 与 Y_i 是否在同一集合内,是的输出
`Y` ;否则输出 `N` 。
## 输出格式
对于每一个 Z_i=2 的操作,都有一行输出,每行包含一个大写字母,为 `Y` 或者 `N` 。
## 样例 #1
### 样例输入 #1
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
### 样例输出 #1
N
Y
N
Y
## 提示
1<=N<=10000,1<=M<=200000,1<=x<=y<=N;
大体思路:我们在输入z,x,y的时候就开始进行判断,如果x与y是对应的数组中的值相同,也就是他们是’父与子‘的关系,我们就输出Y,如果数组中的值不相同,那就代表着他们不是‘父与子’的关系,我们就输出N,注意:在判断时,是将偏向右边的看作是更大的,偏向左边的视为较小的
#include<bits/stdc++.h>
using namespace std;
int arr[10005],n,m;
void init()
{
for(int i=1;i<=n;i++)
arr[i]=i;
}
int getf(int v)
{
if(arr[v]==v)
return v;
else
{
arr[v]=getf(arr[v]);
return arr[v];
}
}
void merge(int x,int y)
{
int t1=getf(x);
int t2=getf(y);
if(t1!=t2)
arr[t2]=t1;
return ;
}
void judge(int x,int y)
{
if(getf(x)==getf(y))
cout<<"Y"<<endl;
else
cout<<"N"<<endl;
}
int main()
{
cin>>n>>m;
init();
int z,x,y;
for(int i=0;i<m;i++)
{
cin>>z>>x>>y;
if(z==1)
merge(x,y);
else
judge(x,y);
}
}