一道高精度加法(/乘法)+HashTable的题。
题目连接在此。
大整数运算相关内容,请看这里。
题意
给出一个长度不超过20的整数,问这个数翻倍后的数位是否为原数数位的一个排列。
如样例:
原数:1234567899(1~8出现一次,9出现2次)
翻倍之后: 2469135798(1~8出现一次,9出现2次)
故倍数数位是原数的数位的一个全排列。
解题思路
- 先进行高进度加法(或乘法)的计算,算出倍数
- 用一个hashTable数组记录原数中每个数(0~9)出现的次数,即hashTable[i]=n表示i出现了n次
- 倍数的每一位对应的hashTable值减1,只要hashTable中(0~9)有一位出现了不为0的情况,则输出No,否则输出Yes。最后并输出倍数的值。
AC代码
加法(add函数)和乘法(multi函数)的实现均在以下代码中。
#include<stdio.h>
#include<cstring>
struct bign{ //big number
int num[25];
int len;
bign(){
memset(num, 0, sizeof(num));
len = 0;
}
};
using namespace std;
bign add(bign a, bign b){ //大整数加法
bign res;
int carry = 0; //进位
for(int i = 0; i<a.len || i<b.len; i++){ //以位数多的数为基准
carry = a.num[i]+b.num[i]+carry;
res.num[i] = carry%10;
carry /= 10;
res.len++;
}
res.num[res.len++] = carry;
//去除前导0
while(res.len-1 >= 1 && res.num[res.len-1] == 0){ //将res.len-1想成数组下标会便于理解
res.len--;
}
return res;
}
bign multi(bign a){ //高精度与低精度乘法 (题目为a.num * 2)
bign res;
int carry = 0;
for(int i = 0; i < a.len; i++){
int temp = a.num[i] * 2;
res.num[i] = temp % 10 + carry;
carry = temp / 10;
res.len++;
}
while(carry != 0){ //乘法的进位可能不止一位 (本题是乘以2,故进位最多为一位)
res.num[res.len++] = carry % 10;
carry /= 10;
}
//去除前导零
while(res.num[res.len-1] == 0 && res.len-1 >= 1) {
res.len--;
}
return res;
}
int main(){
bign a;
char temp[25];
scanf("%s",&temp);
//为输入的a打表用
int hashTable[10] = {0}; //hashTable[i]记录了数字i(0~9)出现的次数
//将temp转换成int型,逆序放入a
a.len = strlen(temp);
for(int i = 0; i < a.len; i++){
int x = temp[i] - '0';
a.num[a.len-1-i] = x;
hashTable[x]++;
}
// bign res = add(a, a); //大数加法
bign res = multi(a); //高精度与低精度乘法
for(int i = 0; i < res.len; i++){
hashTable[res.num[i]]--;
}
//检测并输出结果
bool flag = true; //翻倍之后的数是否是a的全排列的标志
for(int i = 0; i < 10; i++){
if(hashTable[i] != 0) { //不是a的排列
printf("No\n"); //输出No
flag = false;
break;
}
}
if(flag){
printf("Yes\n"); //是a的排列 ,输出Yes
}
for(int i = res.len-1; i >= 0; i--){ // 输出结果
printf("%d",res.num[i]);
}
printf("\n");
return 0;
}
注意点:
1. 不论是输出Yes还是No,最后都要输出倍数的值
2. 还可以用大整数乘法实现(大整数知识点总结)