PTA的链表其实和力扣的挺不一样的,PTA的其实都是用数组来模拟的,而且往往并不限制新开一个数组。出题模式比较固定。因此固定套路是把链表问题变成数组问题来做:
1.开一个装有结构体Node的固定数组,脚标为地址,模拟指针用。
2.从start给的地址开始遍历链表,把链表按顺序放入一个vector中。
3.根据给的条件来变换数组。将结果保存在ans数组中,最后打印出来。
1165.19冬季第二题
大意:Given a singly linked list L. Let us consider every K nodes as a block (if there are less than K nodes at the end of the list, the rest of the nodes are still considered as a block). Your job is to reverse all the blocks in L. For example, given L as 1→2→3→4→5→6→7→8 and K as 3, your output must be 7→8→4→5→6→1→2→3。
每隔K个数认为是一个整体,然后整体大块颠倒顺序,但整体内部顺序不变。
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <queue>
using namespace std;
struct Node
{
int val;
int add, next;
};
const int maxnum = 100005;
int S, N, K;
Node a[maxnum];
int main()
{
cin >> S >> N >> K;
for (int i = 0; i < N; i++)
{
Node node;
cin >> node.add >> node.val >> node.next;
a[node.add] = node;
}
vector<Node> vec;
for (int i = S; i != -1; i = a[i].next)
vec.push_back(a[i]);
int len = vec.size();
vector<Node> ans(len);
int remain = len % K;
int m; //位置i经过变换后在第m个大块
int j = 0;//i在当前大块中的第j个小位置
for (int i = 0; i < len; i++)
{
if (i < len - remain)
{
int m = (len - i) / K - 1;
ans[K * m + remain + j] = vec[i]; //大块数量* m + 一定在最前面的remain部分 + 块内位置
j = (j + 1) % K;
}
else
ans[i - len + remain] = vec[i];
}
for (int i = 0; i < ans.size(); i++)
{
if (i != ans.size() - 1)
printf("%05d %d %05d\n", ans[i].add, ans[i].val, ans[i + 1].add);
else
printf("%05d %d -1", ans[i].add, ans[i].val);
}
return 0;
}
1133
大意:Given a singly linked list, you are supposed to rearrange its elements so that all the negative values appear before all of the non-negatives, and all the values in [0, K] appear before all those greater than K. The order of the elements inside each class must not be changed. For example, given the list being 18→7→-4→0→5→-6→10→11→-2 and K being 10, you must output -4→-6→-2→7→0→5→10→18→11。
负数放最前面,然后大于0小于K的放中间,大于K的放最后。但不改变初始内部顺序。
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <queue>
using namespace std;
struct Node
{
int val;
int add, next;
};
const int maxnum = 100005;
int S,N,K;
Node a[maxnum];
vector<Node> vec;
int main()
{
cin >> S >> N >> K;
for (int i = 0; i < N; i++)
{
Node node;
cin >> node.add >> node.val >> node.next;
a[node.add] = node;
}
for (int i = S; i != -1; i = a[i].next)
vec.push_back(a[i]);
vector<Node> res;
for (int i = 0; i < vec.size(); i++)
{
if (vec[i].val < 0)
res.push_back(vec[i]);
}
for (int i = 0; i < vec.size(); i++)
{
if (vec[i].val >= 0 && vec[i].val <= K)
res.push_back(vec[i]);
}
for (int i = 0; i < vec.size(); i++)
{
if (vec[i].val > K)
res.push_back(vec[i]);
}
for (int i = 0; i < res.size(); i++)
{
if (i != res.size() - 1)
printf("%05d %d %05d\n", res[i].add, res[i].val, res[i + 1].add);
else
printf("%05d %d -1\n", res[i].add, res[i].val);
}
return 0;
}
1161.合并并且倒置链表
大意:给俩链表,让你把短的那个转置了,每隔两个节点拼到长的那个上面。
这题在用套路之前,是一道经典的reverse链表的题目,传统方法硬做也是可以的。这种逻辑简单,但在打印那边其实容易出错。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
struct Node {
int val;
int add, next;
};
const int maxnum = 100005;
Node a[maxnum];
int reverselink(int s)
{
int prev = -1,i = s;
while(i != -1)
{
int tmp = a[i].next; //tmp = cur->next
a[i].next = prev; //cur->next = prev
prev = i; //prev = cur
i = tmp; //cur = tmp
}
return prev;
}
int main()
{
int s1, s2, n;
cin >> s1 >> s2 >> n;
for (int i = 0; i < n; i++)
{
Node node;
cin >> node.add >> node.val >> node.next;
a[node.add] = node;
}
int s1num = 0, s2num = 0;
for (int i = s1; i != -1; i = a[i].next) //遍历第一条链表
++s1num;
for (int i = s2; i != -1; i = a[i].next) //遍历第二条链表
++s2num;
int s,l;
if (s1num < s2num)
{
s = s1;
l = s2;
}
else
{
s = s2;
l = s1;
}
int newhead = reverselink(s); //反转短链表
int p = l, q = newhead;
while (p != -1 && q != -1) //两个链表都没插入完
{
printf("%05d %d %05d\n", p, a[p].val, a[p].next);
p = a[p].next;
printf("%05d %d %05d\n", p, a[p].val, q); //断链连接q
printf("%05d %d ", q, a[q].val); //连接下一个p
if (a[p].next != -1)
printf("%05d\n", a[p].next);
else
printf("-1\n");
p = a[p].next;
q = a[q].next;
}
while (p != -1)
{
if(a[p].next != -1)
printf("%05d %d %05d\n", p, a[p].val, a[p].next);
else
printf("%05d %d -1\n", p, a[p].val);
p = a[p].next;
}
while (q != -1)
{
if (a[q].next != -1)
printf("%05d %d %05d\n", q, a[q].val, a[q].next);
else
printf("%05d %d -1\n", q, a[q].val);
q = a[q].next;
}
return 0;
}
所以还是套路好用,只要来一波小学生找规律即可。在纸上把原来链表的位置写出来,再把例子中的写出来,用i以及间隔k(本题中直接就是2,简化了)来控制变化方法,自己拟合一个公式出来即可。 由于最后结果在一个ans中,打印不容易出错。
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <queue>
using namespace std;
struct Node
{
int val;
int add, next;
};
int s1, s2, N;
const int maxnum = 100005;
Node a[maxnum];
int main()
{
cin >> s1 >> s2 >> N;
for (int i = 0; i < N; i++)
{
Node node;
cin >> node.add >> node.val >> node.next;
a[node.add] = node;
}
vector<Node> v1, v2;
for (int i = s1; i != -1; i = a[i].next)
v1.push_back(a[i]);
for (int i = s2; i != -1; i = a[i].next)
v2.push_back(a[i]);
if (v1.size() > v2.size()) //把v1永远搞成小的那个
{
vector<Node> tmp = v1;
v1 = v2;
v2 = tmp;
}
vector<Node> ans(N);
int m;
for (int i = 0; i < v2.size(); i++)
{
m = i / 2;
ans[m + i] = v2[i]; //其实就是脚标变化找规律而已
}
reverse(v1.begin(), v1.end()); //颠倒短的
int j = 2;
for (int i = 0; i < v1.size(); i++)
{
ans[i * 2 + j] = v1[i]; //小学找规律,一定要耐心
++j;
}
for (int i = 0; i < ans.size(); i++)
{
if (i != ans.size() - 1)
printf("%05d %d %05d\n",ans[i].add,ans[i].val,ans[i+1].add);
else
printf("%05d %d -1\n", ans[i].add, ans[i].val);
}
return 0;
}