[算法笔记-最全的PAT解答]PAT乙级1021-1025题解

每天进步一点点,欢迎交流

1021 个位数统计

给定一个 k 位整数 N=d​k−110k−1+⋯+d​1101+d0(0≤di≤9, i=0,⋯,k−1, dk−1​​ >0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311,则有 2 个 0,3 个 1,和 1 个 3。

输入格式:
每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N。

输出格式:
对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

输入样例:
100311

输出样例:
0:2
1:3
3:1

要点:既然是统计不超过1000位的整数,那肯定没办法用任何类型来存储,只能使用string类型来存储了。而每一位,比如’9’->cnt[9],因为要统计每一位的个数,而数字无非就是0-9,用一个int型数组cnt[10]来存储刚刚好。

#include<iostream>
#include<cstdio>
using namespace std;
int cnt[10];
int main(){
	string s;
	cin >> s;
	for(int i = 0 ; i < s.length() ; i++){
		int num = s[i] - '0';
		cnt[num]++;
	}
	for(int i = 0;i<10;i++){
		if(cnt[i]){
			printf("%d:%d\n",i,cnt[i]);
		}
	}
	return 0;
} 

D进制的A+B

输入两个非负 10 进制整数 A 和 B (≤2​30 −1),输出 A+B 的 D (1<D≤10)进制数。

输入格式:
输入在一行中依次给出 3 个整数 A、B 和 D。

输出格式:
输出 A+B 的 D 进制数。

输入样例:
123 456 8

输出样例:
1103

要点:首先判断A+B的类型用int类型就可以存放了,int d就好,题目的意思是求A+B的D进制数,利用转换进制常见的手段:除数取余法即可解决,需要注意的是输出的顺序应该是从高位往低位输出,至于为什么,你自己用演算纸画一下就知道了

#include<cstdio>
int main(){
	int a,b,d;
	scanf("%d %d %d",&a,&b,&d);
	int sum = a+b;
	int ans[31],num = 0;
	do{
		ans[num++] = sum%d;
		sum/=d;
	}while(sum!=0);
	for(int i = num-1;i>=0;i--){
		printf("%d",ans[i]);
	}
	return  0;
}

1023 组个最小数

给定数字 0-9 各若干个。你可以以任意顺序排列这些数字,但必须全部使用。目标是使得最后得到的数尽可能小(注意 0 不能做首位)。例如:给定两个 0,两个 1,三个 5,一个 8,我们得到的最小的数就是 10015558。

现给定数字,请编写程序输出能够组成的最小的数。

输入格式:
输入在一行中给出 10 个非负整数,顺序表示我们拥有数字 0、数字 1、……数字 9 的个数。整数间用一个空格分隔。10 个数字的总个数不超过 50,且至少拥有 1 个非 0 的数字。

输出格式:
在一行中输出能够组成的最小的数。

输入样例:
2 2 0 0 0 3 0 0 1 0

输出样例:
10015558

要点:本题的做法显然是贪心,既然要在一行中输出最小的数,那么肯定是每次输出的顺序应该都是从当前最小的数开始,当然,首位不能是0,因为首位从1-9中存在的最小的数开始输出。
代码:

#include<cstdio>
int main(){
	int cnt[10];
	for(int i = 0;i<10;i++){
		scanf("%d",&cnt[i]);
	}
	for(int i = 1;i<10;i++){
		if(cnt[i]>0){
			printf("%d",i);
			cnt[i]--;
			break;
		}
	}
	for(int i = 0;i<10;i++){
		for(int j = 0;j<cnt[i];j++){
			printf("%d",i);
		}
	}
	return 0;
}

1024 科学计数法

科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [±][1-9].[0-9]+E[±][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指数部分的正负号即使对正数也必定明确给出。

现以科学计数法的格式给出实数 A,请编写程序按普通数字表示法输出 A,并保证所有有效位都被保留。

输入格式:
每个输入包含 1 个测试用例,即一个以科学计数法表示的实数 A。该数字的存储长度不超过 9999 字节,且其指数的绝对值不超过 9999。

输出格式:
对每个测试用例,在一行中按普通数字表示法输出 A,并保证所有有效位都被保留,包括末尾的 0。

输入样例 1:
+1.23400E-03

输出样例 1:
0.00123400

输入样例 2:
-1.2E+10

输出样例 2:
-12000000000

要点:对于这一题,题解我并没有完全搞懂,但大概意思是,根输入样例分别对情况进行处理,+/-是一端;+/-到E之间的字符串又是一端;E之后的字符串又是一段。
代码:

#include<iostream>
using namespace std;
int main(){
	string s;
	cin>>s;
	int i = 0;
	while(s[i]!='E')i++;
	string t = s.substr(1,i-1);
	int n = stoi(s.substr(i+1));
	if(s[0] == '-')cout<<"-";
	//behind E is a negative number 
	if(n<0){
		cout<<"0.";
		for(int j = 0;j<abs(n)-1;j++)cout<<'0';
		for(int j = 0;j<t.length();j++){
			if(t[j]!='.')cout<<t[j];
		}
	}
	//behind E is a positive number
	else{
		cout<<t[0];
		int cnt , j ;
		for(j=2,cnt=0;j<t.length()&&cnt<n;j++,cnt++)cout<<t[j];
		if(j==t.length()){
			for(int k=0;k<n-cnt;k++){
				cout<<'0';
			}
		}else{//else这一部分没搞懂 
			cout<<'.';
			for(int k = j;k<t.length();k++)cout<<t[k];
		}
	}
	return 0;
}

1025 反转链表

给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转。例如:给定 L 为 1→2→3→4→5→6,K 为 3,则输出应该为 3→2→1→6→5→4;如果 K 为 4,则输出应该为 4→3→2→1→5→6,即最后不到 K 个元素不反转。

输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤10
​5
​​ )、以及正整数 K (≤N),即要求反转的子链结点的个数。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

接下来有 N 行,每行格式为:

Address Data Next

其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。

输出格式:
对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

要点:reverse那块操作还是没搞懂,程序是如何实现data后面的next也变化的???
代码:

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	//第一个结点的地址 结点总个数正整数N K即反转的子链结点的个数 
	int first , k , n , temp;
	cin >> first >> n >> k;
	int data[100005] , next[100005] , list[100005];
	for(int i = 0;i<n;i++){
		cin >> temp ;
		cin >> data[temp] >> next[temp];
	} 
	int sum = 0;
	while(first != -1){
		list[sum++] = first;
		first = next[first];
	}
	//cannot understand
	//-----
	for(int i = 0;i<(sum-sum%k);i+=k){
		reverse(begin(list)+i,begin(list)+i+k);
	}
	//-----
	for(int i = 0;i<sum-1;i++){
		printf("%05d %d %05d\n",list[i],data[list[i]],list[i+1]);
	}
	printf("%05d %d -1",list[sum-1],data[list[sum-1]]);
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值