4273.链表合并
y总讲解里有说,只要不是面试我们就尽量用数组去模拟链表,这样省时省力。
下面简单分析一下这个问题
(1).他说了5位数,那么可以开一个1e5+10的数组就足够了,这样就解决了地址问题,然后权重就是地址存放的值就可以了,但是我们要存放他的next。
(2)所以还需要开一个数组,我们读取完数据,就处理合并就可以了,注意这里我们默认大小的,所以记得if判断一下,然后我们将两个模拟链表顺序存储一下。
(3)借用pair和vector,pair里面是地址和内容,这里我们就不用存储next了,因为我们可以直接用第二个数据的地址就行了,因为我们这里已经给他串连起来了。
(4)最后就是处理一下合并问题,以及输出即可。我这里用的cout处理宽度和前补0麻烦一些,可以选择使用printf来处理会容易很多。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
typedef pair<int, int> PII;
#define x first
#define y second
int head1,head2,n;
int v[maxn],ne[maxn];
int main()
{
cin >>head1>>head2>>n;
while(n--){
int address,value,next;
cin >>address>>value>>next;
v[address] = value;
ne[address] = next;
}
vector<PII> a,b;
for(int i=head1; i!=-1; i=ne[i]) a.push_back({i,v[i]});
for(int i=head2; i!=-1; i=ne[i]) b.push_back({i,v[i]});
if(a.size()<b.size()) swap(a,b);
vector<PII> c;
for(int i=0,j=b.size()-1; i<a.size(); i+=2,j--){
c.push_back(a[i]);
if(i+1< a.size() ) c.push_back(a[i+1]);
if(j>=0) c.push_back(b[j]);
}
for(int i=0; i<c.size(); i++){
cout<<setfill('0')<<setw(5)<<c[i].x<<" "<<c[i].y<<" ";
if(i+1 <c.size()) cout<<setfill('0')<<setw(5)<<c[i+1].x<<endl;
else cout<<"-1"<<endl;
}
return 0;
}
4274.后缀表达式
(1)题目读完了,我们就知道了,递归进行后续遍历,然后记得每个数据都要加个左右括号就行了。
(2)不过我们遍历的时候注意正负号问题,还有他的儿子的处理问题,如果是有俩儿子,那么要输出左右再递归,如果没有儿子直接递归就行了,如果只有一个儿子那也要先输出再递归
(3)最后就是我们如何找到根节点,根节点的特点就是没有父亲节点,利用这一点来找到根节点,我们对所有的儿子节点进行标记,最后没有标记的就是根节点了。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=30;
int n;
string a[maxn];
int l[maxn],r[maxn];
bool st[maxn]; //判断是否有儿子
void dfs(int dd)
{
cout<<"(";
if(st[l[dd]] && st[r[dd]]){
dfs(l[dd]);
dfs(r[dd]);
cout<<a[dd];
}else if(!st[l[dd]] && !st[r[dd]]){
cout<<a[dd];
}else{
cout<<a[dd];
dfs(r[dd]);
}
cout<<")";
}
int main()
{
cin >>n;
for(int i=1; i<=n; i++){
cin >>a[i]>>l[i]>>r[i];
if(l[i]!=-1) st[l[i]] = true; //是否有左儿子
if(r[i]!=-1) st[r[i]] = true; //是否有右儿子
}
int dd;
for(int i=1; i<=n; i++){
if(!st[i]){
dd = i; //找到根节点
}
}
dfs(dd); //开始从根节点进行递归查找
return 0;
}
4275.Dijkstra序列
题目读起来有一点复杂,总结一下就是读入数据后,有K个序列,我们要判断他们是不是Dijkstra序列,也就是跑K次的Dijkstra算法,然后我们来看一下复杂度,题目给的是1000,2s大概是2e8,Dijkstra的朴素写法复杂度是n²级别的,然后算上K大概刚好1e8,可以尝试一下。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1010;
int n,m; //点 和 边
int dist[maxn],g[maxn][maxn]; //距离数组 和 读入数据点的数组
bool st[maxn]; //判断当前点是否遍历过
int dd[maxn]; //测试序列数组
bool dijkstra()
{
memset(dist, 0x3f3f, sizeof dist);
memset(st, 0, sizeof st);
dist[dd[0]] = 0; //起始点
for(int i=0; i<n; i++){
int q = dd[i];
for(int j=1; j<=n; j++){
if(!st[j] && dist[j]<dist[q]){
return false;
}
}
st[q] = true;
for (int j = 1; j <=n; j ++ ){
// if(dist[j] > dist[q] + g[q][j]){
// dist[j] = dist[q] + g[q][j];
// }
dist[j] = min(dist[j],dist[q]+g[q][j]);
}
}
return true;
}
int main()
{
cin >>n>>m;
memset(g, 0x3f3f3f3f, sizeof g); //初始化边
while(m--){
int a,b,c;
cin >>a>>b>>c;
g[a][b] = g[b][a] = c;
}
int k;
cin >>k;
while(k--){
for(int i=0; i<n; i++){
cin >>dd[i];
}
if(dijkstra()) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
有问题欢迎留言,和我交流。