1079-延迟的回文数(PAT-B)

20 篇文章 0 订阅

题目如下:

给定一个 k+1 位的正整数 N,写成 a k . . . a 1 a 0 a_k...a_1a_0 ak...a1a0的形式,其中对所有 i 有 0 ≤ a i &lt; 10 0≤a_i&lt;10 0ai<10 a k &gt; 10 a_k&gt;10 ak>10。N 被称为一个回文数,当且仅当对所有 i 有 a i = a k − i a_i = a_{k-i} ai=aki。零也被定义为一个回文数。非回文数也可以通过一系列操作变出回文数。首先将该数字逆转,再将逆转数与该数相加,如果和还不是一个回文数,就重复这个逆转再相加的操作,直到一个回文数出现。如果一个非回文数可以变出回文数,就称这个数为延迟的回文数。(定义翻译自 https://en.wikipedia.org/wiki/Palindromic_number )
给定任意一个正整数,本题要求你找到其变出的那个回文数。
输入格式:

输入在一行中给出一个不超过1000位的正整数。
输出格式:

对给定的整数,一行一行输出其变出回文数的过程。每行格式如下

A + B = C
其中 A 是原始的数字,B 是 A 的逆转数,C 是它们的和。A 从输入的整数开始。重复操作直到 C 在 10 步以内变成回文数,这时在一行中输出 C is a palindromic number.;或者如果 10 步都没能得到回文数,最后就在一行中输出 Not found in 10 iterations.。
输入样例 1:

97152
输出样例 1:

97152 + 25179 = 122331
122331 + 133221 = 255552
255552 is a palindromic number.
输入样例 2:

196
输出样例 2:

196 + 691 = 887
887 + 788 = 1675
1675 + 5761 = 7436
7436 + 6347 = 13783
13783 + 38731 = 52514
52514 + 41525 = 94039
94039 + 93049 = 187088
187088 + 880781 = 1067869
1067869 + 9687601 = 10755470
10755470 + 07455701 = 18211171
Not found in 10 iterations.

解决方案:

第一次做的时候最后一个测试样例没有通过,后来上网看大佬解释以后说最后一个测试用例是1000位的正整数相加,应该使用大整数高精度加法来计算,没办法,只好推倒原来的代码重写,正好最近刚学习了一些STL,因此我使用了一些STL来解决这个题,顺便巩固一下STL的东西。当然,这一版本的代码还是有些臃肿和复杂,留待以后再进行优化和重构。

1.思路:本题的思路其实并不复杂,按照题目描述:“首先将该数字逆转,再将逆转数与该数相加,如果和还不是一个回文数,就重复这个逆转再相加的操作,直到一个回文数出现。如果一个非回文数可以变出回文数,就称这个数为延迟的回文数。这正好就是本题的思路;做一个递归函数,如果满足上述条件,就退出递归,如果超出十次,就给出相应的输出。而本题的重点和难点则在于如何实现大整数的逆转相加。只要解决这个问题,就可以解出本题。

2.大整数的存储:因为题目给的整数位数较大,所以使用string字符串来存储整数,当然,在计算的时候,还需要将string字符串转换为int型数组来进行大整数相加运算。因为不知道整数的位数,所以使用STL容器vector来存储string字符串转换来的整形数组。
这部分的代码为:

    vector<int> a;
	vector<int> b;
	string aa = str;
	for(int i = 0; i < aa.length(); i++) {
		a.push_back(str[i] - '0');
	}
	reverse(str.begin(), str.end());   //STL中的reverse函数可以对字符串进行反转操作
    string bb = str;
	for(int i = 0; i < bb.length(); i++) {
		b.push_back(str[i] - '0');
	}

3.大整数的相加:大整数的相加还是从《算法笔记》上学的基本思路。在这里重新整理一下,这里就拿样例输入97152来举例:
我们平常用竖式计算的方法是这样的:每一位相加,遇到进位的时候就进位。而大整数相加的方法和竖式计算是一样的,数组的每一位相加,遇到进位的时候就进位,然后将每一位数字存储进数组中。
在这里插入图片描述
大整数相加在算法笔记中的代码是这样的:

//因为竖式计算是从后往前的计算,所以数组需要逆着赋值。也就是说97152赋值进来的时候应该是25179.
int carry = 0;    //carry是进位
for(int i = 0; i < a.len || b.len; i++) {
    int temp = a[i] + b[i] + carry;     //两个对应位与进位相加
    c[i++] = temp % 10;     //个位数位该位的结果
    carry = temp / 10;     //十位数位新的进位
}
if(carry != 0) c[i++] = carry;     //如果最后进位不为0,则直接赋值给结果的最高位。
/*可以手动执行一下代码来加固一下思路和记忆:
第0次循环:a[0] = 2,b[0] = 9,a[0] + b[0] + carry = 9 + 2 + 0 = 11
         c[0] = 11 % 10 = 1 这是个位数的数字
         carry = 11 / 10 = 1 这是进位
第1次循环:a[1] = 5,b[0] = 7,a[0] + b[0] + carry = 5 + 7 + 1 = 13  这已经加上了上一次的进位
         c[1] = 13 % 10 = 3 这是十位数的数字
         carry = 13 / 10 = 1 这是进位
后面以此类推。。。。。。

但是,在《算法笔记》中,为了方便竖式从后往前的计算,人家的数组是逆着赋值的但是因为我没有逆着赋值,而且同样使用了算法笔记中的这种思路,那么如果同样使用竖式计算的话,结果就变成了从前往后的计算,就成了下面这个样子
从前往后的竖式计算
这明显是错误的,因为其正好成了正确数字的逆转。那么现在就需要一个容器,这个容器可以使先放进去的数后出来,很明显,应该使用容器-----栈。
所以,这部分的代码为:

    stack<int> c;
    int carry = 0;
	int temp = 0;
	for(int i = 0; i < max(aa.size(), bb.size()); i++) {
		temp = a[i] + b[i] + carry;
		c.push(temp % 10);
		carry = temp / 10;
	}
	if(carry != 0) c.push(carry);
	int size = c.size();   //防止c.size在弹出栈顶元素的时候减小
	char m[2000];
	for(int i = 0; i < size; i++) {   //这里一定不能使用c.size(),因为栈顶元素会弹出使得c.size()减小
		sprintf(&m[i], "%d", c.top());  //将数组转换为字符串
		c.pop();
	}
	string cc = m;

完整代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
int calculate(string str, int times)
{
	if(times > 9) {
		cout << "Not found in 10 iterations." << endl;
		return 0;
	} //第十次就不行
	vector<int> a;
	vector<int> b;
	stack<int> c;
	string aa = str;
	for(int i = 0; i < aa.length(); i++) {
		a.push_back(str[i] - '0');
	}
	reverse(str.begin(), str.end());
    string bb = str;
    if(aa == bb) {
    	cout << aa << " is a palindromic number." << endl;
    	exit(0);
	} //如果是回文数就终止递归,然后输出
	for(int i = 0; i < bb.length(); i++) {
		b.push_back(str[i] - '0');
	}
	//大整数相加
	int carry = 0;
	int temp = 0;
	for(int i = 0; i < max(aa.size(), bb.size()); i++) {
		temp = a[i] + b[i] + carry;
		c.push(temp % 10);
		carry = temp / 10;
	}
	if(carry != 0) c.push(carry);
	int size = c.size();   //防止c.size在弹出栈顶元素的时候减小
	char m[2000];
	for(int i = 0; i < size; i++) {
		sprintf(&m[i], "%d", c.top());
		c.pop();
	}
	string cc = m;
	cout << aa << " + " << bb << " = " << cc << endl;
	times++;
	calculate(cc, times);
}
int main()
{
	string str;
	int times = 0;
	cin >> str;
	calculate(str, times);
}

大神的解答:

柳神同样是从头到尾相加,只不过柳神没有使用数组而是直接拿字符串减去‘0’对应的ASCII码进行计算然后进行了倒置,空间复杂度比我小多了。
附柳神的解析:1079. 延迟的回文数 (20)-PAT乙级真题
附柳神的代码:

#include <iostream>
#include <algorithm>
using namespace std;
string rev(string s) {
    reverse(s.begin(), s.end());
    return s;
}
string add(string s1, string s2) {
    string s = s1;
    int carry = 0;
    for (int i = s1.size() - 1; i >= 0; i--) {
        s[i] = (s1[i] - '0' + s2[i] - '0' + carry) % 10 + '0';
        carry = (s1[i] - '0' + s2[i] - '0' + carry) / 10;
    }
    if (carry > 0) s = "1" + s;
    return s;
}
int main() {
    string s, sum;
    int n = 10;
    cin >> s;
    if (s == rev(s)) {
        cout << s << " is a palindromic number.\n";
        return 0;
    }
    while (n--) {
        sum = add(s, rev(s));
        cout << s << " + " << rev(s) << " = " << sum << endl;
        if (sum == rev(sum)) {
            cout << sum << " is a palindromic number.\n";
            return 0;
        }
        s = sum;
    }
    cout << "Not found in 10 iterations.\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值