难点:如何输出逗号
参考别人的答案,还是把整型数字转为字符串
代码实现如下:
#include
char sumchar[10]; 保存数组
void change(int number){ 把数字转为字符型
int index = 0, times = 0; index是在数组中的下标,times是数字的位数
while(number != 0){
if(times % 3 == 0 && times != 0){
sumchar[index++] = ','; 加上逗号
}
sumchar[index++] = number % 10 + '0'; 数字
number /= 10;
times = times+1; 是数字,位数加1
}
}
int main(){
int a,b = 0;
int sum,i = 0 , end_index = 0;
scanf("%d %d",&a,&b);
sum = a+b;
if(sum < 0){
printf("-");
sum = -sum;
}
change(sum); //这里不太合适,没有考虑0的情况
for(i = 0; sumchar[i] != 0 && i <= 10; i++){
end_index = i; 找到末尾的数字
}
for(i = end_index; i>= 0; i--){
printf("%c", sumchar[i]); 倒序输出
}
return 0;
}
这个有一个极端的用例会出错。
参考别人的代码实现,发现少了结果是0的情况。如果是0,就不会输出任何东西。
有挺多细节需要考虑,突然想到需要倒序输出,是一个后进先出的例子,如果熟练的话可以用栈来实现。
08.31
1、KY2:查找和排序
要求:成绩按照从低到高和从高到低分别排序、输出
限制:无
知识点:排序
卡在:忘记如何对结构体中的变量进行排序了。
参考代码,分别对两种排序用两个函数实现。输出方法也用一个函数来实现了。排序它内部是使用冒泡排序来完成的。
收获:
- struct前面要加typedef
- 定义数组长度时,大小最好不要弄成变量n,可以设一个较大的绝对不会超过的数。
- 字符串和整型数字是可以在同一个scanf中输入的,
scanf("%s %d",a,&b)
即可
但是感觉这种还是比较复杂的,如果可以使用sort()来进行排序,就很简单了。
参考sor()的代码,结构体排序的方法是重新写一个排序函数。如下
bool cmp0(Stu a,Stu b){
if(a.score!=b.score){
return a.score>b.score;
}else{
return a.num
这个是降序排列,如果成绩相等,num小的排在前面
if(temp==1){
std::sort(stu,stu+n,cmp1);
}
else if(temp==0){
std::sort(stu,stu+n,cmp0);
}
如下语句即可完成sort()的调用。
2、求约数的个数
限制:个数n<=1000,每个数字的大小Num<=1000000000
知识点:对大数据的处理
卡在:这么大的数据如何表示
别人代码实现如下:
i*i
using namespace std;
int numOfDivisor(int num)
{
int ans = 0;
int i;
for (i = 1; i*i> n)
{
for (int i = 0; i> num;
cout << numOfDivisor(num) << endl;
}
}
return 0;
}
输入输出在main函数中,求约数是在numDivisor函数中。
这个是最简单的方法,但是耗时也比较大。
还可以用 质数筛法,筛选出所有的质数。(但是这有什么用呢?)有用:如果是质数,就不用再往下判断它有没有因子了,它除了1和它本身,没有其他约数了就。
/*
* 因数个数(使用到质数筛法)
*/
#include
#include
#include
#include
using namespace std;
const int MAXN = 4e4;
bool isPrime[MAXN]; //标记数组
vector prime; //保存质数
void initial(){ //初始化
fill(isPrime,isPrime+MAXN,true);
isPrime[0]=false;
isPrime[1]=false;
for(int i = 2;i exponent;
for(int i = 0;i1){
exponent.push_back(1);
}
int ans = 1;
for(int i = 0;i
初始化其实就是素数筛法,找出所有的质数。
fun()就是求因数的函数。
变量:
vector exp
prime里面放的是所有素数
对每一个素数,分别进行如下操作
factor是当前素数
如果n还可以分解为这个素数,统计出现了多少次这个素数,记在exp栈里面。同时n也除去相应的数。
最终的个数根据之前的一个公式来计算:
(e1+1)(e2+1)(e3+1)....(en+1)
- vector除了可以用来当栈操作,在不使用栈的特性时,也可以单纯地用来计数。
09.01
1、A + B 的多项式形式
限制:K <= 10, N(指数) <= 1000
考察:直接用数组记录即可。(位置表示索引,有点类似哈希)
不要一不会就看答案!多思考!思考是进步的过程!!!
09.03
1、多项式相加
- 对于double型,判断是否为0,最好考虑误差
- C++中,abs要使用头文件cmath,C中使用stdlib.h
输出错误,应该倒序输出
现在的问题在 double型系数不能正确读取,刚才不知道为什么错了,重新改为scanf("%lf",&xishu),即可。
自己代码实现
#include
#include
using namespace std;
double A[11] = {0},B[11] = {0},ans[11] = {0};
int main(){
int Ka,Kb,i;
scanf("%d",&Ka);
int count_num = 0;
int index;
double xishu;
while(Ka--){
scanf("%d %lf",&index, &xishu);
A[index] = xishu;
}
scanf("%d",&Kb);
while(Kb--){
scanf("%d %lf",&index, &xishu);
B[index] = xishu;
}
for(i = 0; i<= 11; i++){
ans[i] = A[i] + B[i];
if( abs(ans[i] - 0) >= 0.00000001){
count_num ++;
}
}
printf("%d",count_num);
for(i = 11; i >= 0; i--){
if(abs(ans[i] - 0) >= 0.00000001)
printf(" %d %l.1f",i,ans[i]);
}
return 0;
}
其实自己弄的复杂了,并且答案还不对。
K是数字的个数,但是n才是系数的个数,所以数组的大小应为N的个数。
还是不知道自己哪里错了,参考别人的代码
#include
const int max_n = 1111;
double a[max_n] = {}; 只用一个来实现就够了
int main(){
int k, n, count = 0;
double e;
scanf("%d", &k);
for(int i = 0; i < k; i ++){
scanf("%d%lf", &n, &e);
a[n] = e;
}
scanf("%d", &k);//这里k只是为了存储,所以这儿k是可以重复存放值。
for(int i = 0; i < k; i ++){
scanf("%d%lf", &n, &e);
a[n] += e;//这儿其实就是有相同的就相加,没有相同的就不想加
}
for(int i = 0; i < max_n; i ++){
if(a[i] != 0){
count ++;
}
}
printf("%d", count);
for(int i = max_n - 1; i >=0; i --){
if(a[i] != 0) printf(" %d %.1f", i, a[i]);
}
return 0;
}
2、Emergency
题目:给出图,找出最短路径。
限制:N(节点数)<500
知识点:印象中,图论用邻接矩阵实现
小细节:最后没空格
参考答案1
需要用到Dijkstra 算法。
设置内存,头文件#include
fill函数,可以设定为任意指定的值,头函数
代码实现过程
1、定义变量,初始化
2、Dijk算法{
找出最小的顶点,标记这个顶点已经计算过了
有两种情况会替换掉原来的值
}
不懂Dijkstra算法为什么有个没有用到的i的for循环
3、Counting Leaves
题目:
限制:N节点数量 < 100,M 非叶子结点的数量
知识点:考察的定义和层次遍历
参考别人代码,可以用dfs,也可以用bfs.
dfs实现如下
头文件
#include
#include
#include 后面有一个max()函数,所以需要algorithm头文件
using namespace std;
定义变量
vector v[100];
int book[100];
int maxDepth=-1;
void dfs(int index,int depth){
// 此时第index结点已经没有子结点了,则表明是叶子结点
if(v[index].size()==0){
// 统计该叶子结点
book[depth]++;
// 更新最大层次
maxDepth = max(maxDepth,depth);
return ;
}
// 递归调用
for(int i=0;i>N>>M){
for(int i=0;i>node>>K;
for(int j=0;j>temp;
v[node].push_back(temp); 把子树的信息输入到v中
}
}
// 从第一个结点开始,第零层
dfs(1,0);
cout<
还可以使用bfs,不同的是,需要额外的数组来统计每个节点所在的层次
逻辑搞懂了其实也不难
4、Spell It Right
题目:求和,字母输出
限制:N(数字) < 10的100次方
知识点:大数存储,每个数字转换为一个字母,数组实现
一道挺简单的题,编译还是有很多错。
首先字母表的定义
8AC9976D-F3F3-4851-B866-9760EE89F209.png
vector不是pop,是pop_back()
原来的结果错误,是因为少了一层digit嵌套。
测试结果发现还有一个段错误,是没有考虑到输出为0的情况,加入为0的情况就正确啦!我人生的第一个AC!!
53EAD403-B5A6-40F2-BF55-D5A951E181B4.png
代码实现如下
#include
#include
using namespace std;
char num[110];
char zimubiao[10][10] = {"zero","one","two","three","four","five","six","seven","eight","nine"};
int main(){
int i;
int ans = 0,flag = 0;
scanf("%s",num);
for(i = 0; num[i]!= 0 && i < 110; i++){
ans += num[i] - '0';
}
vector digit;
flag = ans;
while(ans != 0){
digit.push_back(ans%10);
ans /= 10;
}
if(flag != 0){
printf("%s",zimubiao[digit[digit.size()-1]]);
digit.pop_back();
}
else{
printf("%s",zimubiao[0]);
}
while(digit.size()!= 0){
printf(" %s",zimubiao[digit[digit.size()-1]]);
digit.pop_back();
}
return 0;
}
也可以用数组实现,只计算一个数组有效长度即可。
5、Sign In and Sign Out
题目:签到签退,要求找出最早和最晚时间。
限制:ID_number字符串字符 < 15
知识点:对时间格式的数据进行操作的能力
输入的时候 scanf("%s %d:%d:%d %d:%d:%d",ID,&H1,&M1,&S1,&H2,&M2,&S2);
,这样输入。
比较的时候,都化为秒数去比较。
收获:
不用所有数据都记录,只记录最开始和最后的数据即可,每次输入之后都进行比较。
字符串赋值的时候,先清空,再赋值 strcpy(in,"");strcpy(in,ID);
输出:printf("%s %s",in,out);
6、Maximum Subsequence Sum
题目:最长子序列
知识点:动态规划
限制:数量K <= 10000,如果都是负数,需要特殊处理
j表示以j结尾
变化的过程:dp[i][j] = dp[i][j-1] + v, (❌). dp[i]=max(dp[i],dp[i-1]+a[i])
代码实现如下:
#include
#include
using namespace std;
int a[10005],l[10005],r[10005];
int dp[10005];//以a[i]结尾的最大连续区间和
int main()
{
int n;
cin>>n;
for(int i=0;i>a[i];
dp[i]=a[i];//初始化
} 首先把dp初始化了,所以后面比较的时候就可以拿dp的值比较.
l[0]=r[0]=0;
for(int i=1;i=dp[i])//如果a[i]>=0,且数值变大了
{
dp[i]=dp[i-1]+a[i];
l[i]=l[i-1];//区间左端点不变,右端点更新
r[i]=i;
}
else//如果a[i]是负数,新建一个区间
{
l[i]=i;
r[i]=i;
}
}
int ans=-1,pos=0,flag=0;
for(int i=0;ians)
{
flag=1;
ans=dp[i];
pos=i;
}
}
//cout<
也可以用模拟的方法
#include
#include
#include
#include
#include
#include
#include
思想是:每次都加上一个试试,有最好的结果(更新ans),一般的结果(什么也不做)和最差的结果(归0)。
7、Elevator
题意:电梯升降,计算时间。
限制:所有数 < 100
没有难度,数组计算和之前的差即可。但是答案都错啦?
因为:1没有print 2 i改为下标从1开始之后,没有 <= n
更改之后代码如下:
#include
#include
using namespace std;
int main(){
int n, a[110],diff[110],i;
int ans = 0;
scanf("%d",&n);
a[0] = 0;
for(i = 1; i<= n; i++){
scanf("%d",&a[i]);
diff[i] = a[i] - a[i-1];
}
for(i = 1; i <= n; i++){
if(diff[i] >= 0){
ans += (diff[i]*6) + 5;
}
else
ans += (-diff[i]*4) + 5;
}
printf("%d",ans);
return 0;
}
8、Product of Polynomials
题意:多项式相乘
知识点:仍然是数组的操作
限制: K <= 10,N <= 1000
实现:指数相加,系数相乘
在调试发现输入的方法不对,导致数据篡位
017EADA6-2D40-42F4-A6AD-9A063BF63532.png
初次代码实现:(有错)
#include
#include
#include
double A[1100] = {0},B[1100] = {0},ans[2200] = {0};
int Ka,Kb,N,count = 0;
int main(){
int i = 0, j= 0;
scanf("%d",&Ka);
for(i = 1; i<= Ka; i++){
scanf("%d%lf",&N,&A[N]);
}
scanf("%d",&Kb);
for(i = 1; i<= Kb; i++){
scanf("%d %lf",&N,&B[N]);
}
for(j = 1; j <= 1100; j++){
for(i = 1; i<= 1100; i++){
ans[i+j] += B[i]*A[j];
}
}
for(i = 0; i<= 2200; i++){
if(ans[i] != 0) count++;
}
printf("%d",count);
for(i = 2200; i>= 0; i--){
if(abs(ans[i]) > 1e-5) printf("%d %l.1f",i,ans[i]);
}
return 0;
}
错误:
- 应该先输入N,再输入系数,即给数组矩阵赋值,与确定数组的坐标,不能在同一条语句中。
- for循环计算ans时,这时候算的是系数,从0开始。而K输入时,需要的是K次,若从1开始也没关系,只用计数即可。
09.04
1、A*B 多项式相乘
测试用例正确的,但是提交,答案还是错误.
为什么还是错的,我要疯了。
参考别人答案
#include
#include
using namespace std;
int main()
{
double A[1020]={0.0};
double B[1020]={0.0};
double C[2020]={0.0};
int ka,kb;
cin>>ka;
for(int i = 0;i>nk>>a;
A[nk] = a;
}
cin>>kb;
for(int i = 0;i>nk>>a;
B[nk] = a;
}
for(int i=0;i<=1000;i++)
for(int j=0;j<=1000;j++)
{
C[i+j]+=A[i]*B[j];
}
int count = 0;
for(int i=0;i<=2000;i++)
if(C[i]!=0.0)
count++;
cout<=0;i--)
if(C[i]!=0.0){
cout<<" "<
把scanf 都换位 cout等,就有部分错误了
把最后输出换为printf("%.1lf",ans[i])
部分正确。
还是不知道为什么错,先不管了。
2、Radix
题目:进制转换
限制:N不超过10个数字,
难点:怎么确定进制?要一个一个去试吗?试到最大结束?
参考结果:虽然思路可以,但是超时
可以用二分法来确定
基数的最小值:N2的最大权值 + 1
基数的最大值:N1 + 1
mx用于计算N2的最大权值
真正二分的过程用while来实现
while(l <= r){
......
如果偏大
if(tmp > num1 || tmp < 0)
r = mid - 1;
else if(tmp < num1) {
l = mid + 1;
}
else{
cout << mid;
return 0;
}
}
收获1:
- 该用头文件
#include
万能头文件
- 进制可能是很大的,用longlong型
- 一个非常巧妙的进制转换的方法
for(int i=0;i='0'&&s1[i]<='9')
14 num1+=s1[i]-'0';
15 else
16 num1+=s1[i]-'a'+10;
17 }
3、World Cup Betting
计算、输出题
每一场都选最大的即可
开心!第一次无改错直接编译通过且答案完全正确!!
#include
using namespace std;
double peilv[4][4]; 存放赔率
double ans = 0; 最后结果
char c[3]; 存放标志 WTL
int i = 1,j = 1;
int main(){
for(i = 1; i <= 3; i++){
cin >> peilv[i][j] >> peilv[i][j+1] >> peilv[i][j+2];
peilv[i][0] = max(max(peilv[i][j],peilv[i][j+1]),peilv[i][j+2]);
if (peilv[i][0] == peilv[i][j]) c[i-1] = 'W';
if (peilv[i][0] == peilv[i][j+1]) c[i-1] = 'T';
if (peilv[i][0] == peilv[i][j+2]) c[i-1] = 'L';
}
ans = (peilv[1][0]*peilv[2][0]*peilv[3][0]*0.65 - 1)*2;
cout << c[0] << " " << c[1] << " " << c[2] << " " << ans;
return 0;
}
4、 The Best Rank
题意:找出每个学生最好的排名
限制:N和M < 2000
考察:对数组的操作
思路: A C M E 四门课的N成绩,分别sort排序,结果保存在数组中。
查询的M个人,分别按顺序招,输出排名最靠前的。
我想到的是单纯用数组存储,参考别人,结构体存储更简便。
代码如下
#include
#include
using namespace std;
struct node {
int id, best;
int score[4], rank[4];
}stu[2005];
int exist[1000000], flag = -1;
bool cmp1(node a, node b) {
return a.score[flag] > b.score[flag];
}
int main(void ){
int n, m, id;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++) {
scanf("%d %d %d %d", &stu[i].id, &stu[i].score[1], &stu[i].score[2], &stu[i].score[3]);
stu[i].score[0] = (stu[i].score[1] + stu[i].score[2] + stu[i].score[3]) / 3.0 + 0.5;
}
for( flag = 0; flag <= 3; flag++) {
sort(stu, stu + n, cmp1);
stu[0].rank[flag] = 1;
for(int i = 1; i < n; i++) {
stu[i].rank[flag] = i + 1;
if( stu[i].score[flag] == stu[i-1].score[flag] )
stu[i].rank[flag] = stu[i-1].rank[flag];
}
}
for( int i = 0; i < n; i++) {
exist[stu[i].id] = i + 1;
stu[i].best = 0;
int minn = stu[i].rank[0];
for( int j = 1; j <= 3; j++) {
if( stu[i].rank[j] < minn) {
minn = stu[i].rank[j];
stu[i].best = j;
}
}
}
char c[5] = {'A', 'C', 'M', 'E'};
for( int i = 0; i < m; i++) {
scanf("%d", &id);
int temp = exist[id];
if( temp ) {
int best = stu[temp-1].best;
printf("%d %c\n", stu[temp-1].rank[best], c[best]);
} else {
printf("N/A\n");
}
}
return 0;
}
5、Battle Over Cities
之前做过
限制:N城市数目 < 1000,
其实就是利用深度遍历,根据一个点,把其相邻的所有点都遍历一遍。
6、Waiting in Line
知识点:考察队列、时间 操作
每过一分钟,进行一次操作
#include
#include
using namespace std;
struct Peo{
int time, constTime, leaveTime, ind;
}p[1001];
queue q[21];
int main(int argc, char const *argv[])
{
int N, M, K, Q;
cin >> N >> M >> K >> Q;
for (int i = 1; i <= K; ++i){
cin >> p[i].time;
p[i].ind = i;
p[i].constTime = p[i].time;
}
int index = 1, cnt = 1;
for (int i = 1; i <= 10000; ++i){
while(cnt <= N*M && index<=K){
for (int j = 1; j <= N; ++j){
if(q[j].size()> num;
if(p[num].leaveTime-p[num].constTime<540)
printf("%02d:%02d\n", (p[num].leaveTime+480)/60, (p[num].leaveTime+480)%60);
else printf("Sorry\n");
}
return 0;
}
7、Reversible Primes
题目:素数倒过来也是可逆的
限制:数字N < 10^5 进制D <= 10
写代码:6:53 - 7:10
简单地改错之后,运行超时了。
再改之后,还是答案错误.
疑问:23 ,2这个数组
理解错题意了。
先把23转为二进制,再反过来,再转为10进制,再算是否为素数。
自己写的代码如下:
#include
#include
#include
#include
using namespace std;
char kaishi[8];
int index_q = 7, i;
int D;
int quanzhong = 0;
int num = 0;
bool flag = true;
int main(){
cin >> kaishi >> D;
while(kaishi[0] != '-'){
for(i = 0; i < 7; i++){
if(kaishi[i] == 0){
index_q = i;
break;
}
}
quanzhong = 1;
for(i = 0; i < index_q; i++){
num += (kaishi[i] - '0')*quanzhong;
quanzhong *= D;
}
int bianjie = (int)(sqrt(num)+0.5);
for(i = 2; i< bianjie; i++){
if(num % i == 0 || num %2 == 0){
flag = false;
break;
}
}
if(flag) cout << "Yes" <> kaishi >> D;
}
return 0;
}
参考别人代码如下:
#include
using namespace std;
int main(){
int n,d;
while(cin>>n){
if(n<0)
break;
cin>>d;
int flag=0;
for(int i=2;i*i<=n;++i)
if(n%i==0)
flag=1;
int a[27]={0};
int cnt=0;
while(n){
a[++cnt]=n%d;
n/=d;
}
int x=0;
for(int i=1;i<=cnt;++i){
x*=d;
x+=a[i];
}
if(x==1)
flag=1;
for(int i=2;i*i<=x;++i)
if(x%i==0)
flag=1;
if(flag)
cout<<"No"<<"\n";
else
cout<<"Yes"<<"\n";
}
return 0;
}
收获
8、Phone Bills
题意:计算电话账单
输入:24个数
这是一道考察基本功和逻辑的题,没有太多算法,读懂题意就是算法。
题目有点难懂,其次,要使用map
map中的所有数据都是有序的
用法如下
std:map personnel;
这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.
难度略大,如果真实遇到了大概率放弃
前面有点都是这种数据处理题,倒着开始做
9、Heap Paths
之前测过
题意:遍历每一条路径
限制:节点N <= 1000
考察:堆、深度优先遍历
10、Vertex Coloring
做过
限制:N、M < 10^4
代码实现如下:
#include
#include
#include
using namespace std;
struct node { int t1, t2; };
int main() {
int n, m, k, i;
cin >> n >> m;
vector v(m);
for (i = 0; i < m; i++) cin >> v[i].t1 >> v[i].t2;
cin >> k;
while (k--) {
int color[10009] = { 0 };
bool flag = true;
set se;
for (i = 0; i < n; i++) {
cin >> color[i];
se.insert(color[i]);
}
for (i = 0; i < m; i++) {
if (color[v[i].t1] == color[v[i].t2]) {
flag = false;
break;
}
}
if (flag)
printf("%d-coloring\n", se.size());
else
printf("No\n");
}
return 0;
}
收获:
11、Decode Registration Card of PAT
限制:N card的数量 < 10^4,M查询的数量 < 100
考察:对数据的处理
思路:用结构体来存储每条信息,根据不同的type输出
参考如下文章:
https://blog.csdn.net/liuchuo/article/details/84973049
收获:
- 如果
- 一些库函数,输出时很方便
- auto
12、Google Recruitment
题意:找某个固定数字的素数
考察:素数筛法吧?
是找素数,但是没用素数筛,直接常规的方法
收获:
13、LCA in a Binary Tree
给出树的中序和前序遍历,构建出这棵树,再递归查找公共祖先
09.06
1、上题LCA
我恨自己明明有时间为什么不看他!说不定能多对一道题呢!
虽然没写出来,但是很接近了。
头文件如下
#include
#include
#include
留下了悔恨的泪水
09.07
1、Travelling Salesman Problem
问题:求最短路径,回到原始点
限制:顶点数N < 200, M < 100, 接下来输出K条路径
不懂Dijkstra算法为什么有个没有用到的i的for循环
1、进制转换
题目要求:十进制转为二进制
限制:数字很大,个数可能为30个数字/ 数字是非负数。
难点:数字很长,不能用普通的整型来表示,需要分割、处理等。
正好是上道题说的 用vector来实现
代码实现如下:
#include
#include
#include
using namespace std;
string Divide(string str, int x){
int reminder = 0;
for(int i = 0; i < str.size(); i++){
int current = reminder * 10 + str[i] - '0';
str[i] = current / x + '0';
reminder = current % x;
}
int pos = 0;
while(str[pos] == '0')
pos++;
return str.substr(pos);
}
int main()
{ string str;
while(cin >> str){
vector binary; 对于每次输入,创建一个int 型的binary。
while(str.size() != 0){
int last = str[str.size() - 1] - '0'; 取出来最后的数字
binary.push_back(last % 2); 把最后一位处理,放入
str = Divide(str, 2);
}
for(int i = binary.size() - 1; i >= 0; i--){
cout << binary[i]; 输出
}
cout << endl;
}
return 0;
}
才疏学浅,看不懂。看另一个,通过C语言实现
#include
int conversion(int x,int y,int s[],int d[],int n)
{
int size=0;
int i,j,k;
i=0;
while(i=0;i--) printf("%d",dst[i]);
printf("\n");
}
}
输入的长整型保存在str[]中。使用了一个函数进行转换。把10进制转为2进制。
https://www.nowcoder.com/practice/0337e32b1e5543a19fa380e36d9343d7?tpId=40&&tqId=21332&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
1、A+B for Polynomials
题目:A和B是多项式,求A+ B
限制:k<=10, N <= 1000
2、例题:给定前序和后序,计算中序有几种情况。
这是一个定式,前序,后序给定,划分子问题时,可能有多种左右子树的划分方式,参见柳神对 PAT 1119 的解答,适当变形即可.
知识点:先序中序后序
限制:节点数N <= 30
代码实现
#include
#include
using namespace std;
vector in, pre, post;
bool unique = true;
void getIn(int preLeft, int preRight, int postLeft, int postRight) {
只剩下一个节点了,直接入即可
if(preLeft == preRight) {
in.push_back(pre[preLeft]);
return;
}
根节点符合情况,
if (pre[preLeft] == post[postRight]) {
int i = preLeft + 1; //左子树的开始
while (i <= preRight && pre[i] != post[postRight-1]) i++; //找到右子树的根节点,即左右子树的分界线,用i表示。
if (i - preLeft > 1) //左子树还能再划分
getIn(preLeft + 1, i - 1, postLeft, postLeft + (i - preLeft - 1) - 1);
else //左子树只有一个,或者没有左子树,这个节点来回移动
unique = false; 没懂
in.push_back(post[postRight]);
getIn(i, preRight, postLeft + (i - preLeft - 1), postRight - 1);
}
}
int main() {
int n;
scanf("%d", &n);
pre.resize(n), post.resize(n);
for (int i = 0; i < n; i++)
scanf("%d", &pre[i]);
for (int i = 0; i < n; i++)
scanf("%d", &post[i]);
getIn(0, n-1, 0, n-1);
printf("%s\n%d", unique == true ? "Yes" : "No", in[0]);
for (int i = 1; i < in.size(); i++)
printf(" %d", in[i]);
printf("\n");
return 0;
}
收获:
- 如果出现
reference to 'xxxxxxx' is ambiguous
,可能是定义的变量和库中的某个变量撞名字了,把变量的名字改掉就可以了。
- vector 里面的resize,可以设置内存大小
3、PAT考纲
参考 https://www.jianshu.com/p/3814d99bed25
PAT-A总共有4题,时间为3小时。三四大题 是一题图、一题树的概率较大,偶尔动态规划,贪心算法等。 第二题 一般是STL(map,set,vector为主,偶尔队列,堆栈)。第一题小题(逻辑题,字符串处理,数学,枚举),要么简单,要么读题复杂理解复杂情况不容易想到,但是程序不会太复杂。其他的比如排序、查找、哈希、递归、递推、尺取法、哈夫曼、链表、素数的判断、数学问题、模拟、逻辑什么的,不需要复习,一般都融在题目里,是最基本的,看能力。
https://www.liuchuo.net/999-9
浙大2019原题:
happy 数:任给一个数,求其各位平方和,求迭代到 1 所需次数,或者形成圈的起始数
给定无序数组排序给定宽度并用 Zig zag 输出(PAT 原题)
给定前序判断是否是 avl 树(PAT 原题)
给定图,给定顶点子集,排序输出顶点子集图中度前 3 的点,度相同输出编号小的
https://pintia.cn/problem-sets/994805148990160896/problems/994805156145643520
字符串处理
一个很长(长度为 )的数字字符串,要求删除 () 个数,使得得到的数最小。(60/100)
需要思考的较多,写起来很简单。越大的数,越先删除,对于需要删除的同等大小的数,其余的数都不比他大,所以先删除前面的。但是有特殊情况需要考虑,例如 ,删除 1 位的最佳选择应该是直接删除 而不是 ,因为这样会使最高位得以降低。这种情况需要优先处理。我当时就没有考虑到。
动态规划
男孩女孩排列问题,要求连续男孩的个数不超过 个的可能的排列个数。(70/100)
动态规划问题,划分子问题求解。当时使用的递归结果超时了。
PAT顶级 1004 To Buy or Not to Buy - Hard Version (35分) 不会做
做题还有:九度教程