问题1
Determine whether an integer is a palindrome. Do this without extra space.
class Solution {
public:
bool isPalindrome(int x) {
//判断输入的数合法
if(x<0){
return false;
}
int old_num=x;
int new_num=0;
//倒过来
while(old_num!=0){
int num=old_num%10;
old_num/=10;
new_num*=10;
new_num+=num;
}
if(x==new_num){
return true;
}else{
return false;
}
}
};
问题2
请寻找并输出1至1000000之间的数m,它满足m、m^2和m^3均为回文数。
回文数大家都知道吧,就是各位数字左右对称的整数,例如121、676、123321等。满足上述条件的数如m=11,m^2=121,m^3=1331皆为回文数。
#include <iostream>
using std::cout;
/**
* 请寻找并输出1至1000000之间的数m,它满足m、m^2和m^3均为回文数。
* 回文数大家都知道吧,就是各位数字左右对称的整数,例如121、676、123321等。满足上述条件的数如m=11,m^2=121,m^3=1331皆为回文数。
*/
bool isPalindrome(long long x) {
//判断输入的数合法
if (x < 0) {
return false;
}
long long old_num = x;
long long new_num = 0;
//倒过来
while (old_num != 0) {
long long num = old_num % 10;
old_num /= 10;
new_num *= 10;
new_num += num;
}
if (x == new_num) {
return true;
} else {
return false;
}
}
int main() {
//1 - 1000000
int line=0;
for(long long i=1;i<=1000000;i++){
long long i2=i*i;
long long i3=i*i*i;
if(isPalindrome(i) && isPalindrome(i2) && isPalindrome(i3)){
cout<<i;
line++;
if(line==5){
cout<<"\n";
line=0;
}else{
cout<<" ";
}
}
}
}
求一个数是否是回文数的变种,利用问题1。
要注意的是,数的范围很大,所以类型不是int,而是long long。
问题3
输入一个字符串,求出其中最长的回文子串。
子串的含义是:在原串连续出现的字符串片段。
回文的含义是:正着看和倒着看是相同的,如abba和abbebba。
在判断是要求忽略所有的标点和空格,且忽略大小写,但输出时按原样输出(首尾不要输出多余的字符串)。
输入字符串长度大于等于1小于等于5000,且单独占一行(如果有多组答案,输出第一组)。
#include <iostream>
#include <string>
using namespace std;
/**
* 输入一个字符串,求出其中最长的回文子串。
* 子串的含义是:在原串连续出现的字符串片段。
* 回文的含义是:正着看和倒着看是相同的,如abba和abbebba。
* 在判断是要求忽略所有的标点和空格,且忽略大小写,但输出时按原样输出(首尾不要输出多余的字符串)。
* 输入字符串长度大于等于1小于等于5000,且单独占一行(如果有多组答案,输出第一组)。
*/
const int MAXN=5000;
int p[MAXN];
char tempStr[MAXN];
bool isValid(string str){
if(str.length()<1 || str.length()>5000){
return false;
}
}
void huiwenMain(string str){
//输入是否合法
isValid(str);
//全部变成大写
int m=0;
for(int i=0;i<str.length();i++){
if(isalpha(str[i])){
p[m]=i;
tempStr[m]=toupper(str[i]);
m++;
}
}
//i是中间位置下标 maxLength是目前最长子串长度 j是距离 begin是回文串起始下标 end是终止下标,可以直接对应p,映射回str
int maxLength=0;
int begin=0;
int end=0;
for(int i=0;i<m;i++){
//如果回文串是奇数个数字符
for(int j=0;j<=i && i+j<m;j++){
//abcba
if(tempStr[i-j]!=tempStr[i+j]){
break;
}
//成功了一个
if(2*j+1>maxLength){
maxLength=2*j+1;
begin=p[i-j];
end=p[i+j];
}
}
//如果回文串是偶数个数字符
//只要计算偶数靠左的方案
//首先要判断与下一个是相同的
if(i+1<m && tempStr[i]==tempStr[i+1]){
for(int j=0;j<=i && i+j+1<m;j++){
if(tempStr[i-j]!=tempStr[i+j+1]){
break;
}
if(2*j+2>maxLength){
begin=p[i-j];
end=p[i+j+1];
}
}
}
}
//cout出str
for(int i=begin;i<=end;i++){
cout<<str[i];
}
}
int main() {
huiwenMain("Confuciuss say:Madam,I'm Adam.");
return 0;
}
思想:
(1)不区分大小写,所有字符转化为大写,标点空格等字符除外。
(2)输出时按照原样输出,就要想到需要两个数组,一个数组储存有效的字符(意思是非逗号);另一个数组相应储存这个有效字符在原字符串中的下标。
(3)按照中间位置循环,尝试不同距离得出最长的回文串。这里要考虑到奇数个字符还是偶数个字符。得到有效最长回文串,记录一头一尾两个下标,就可以cout了。
问题4
所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如”aba”。
当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。
要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
#include <iostream>
using namespace std;
/**
* 所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba"。
* 当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。
* 要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
*/
bool isValid(string str,int length,int right);
int addCharMain(string str,int left,int right);
bool isInputValid=false;
int addChar(string str,int left,int right){
if(isValid(str,left,right)){
return 0;
}
isInputValid= true;
int val=0;
val=addCharMain(str,left,right);
cout<<val;
}
bool isValid(string str,int left,int right){
if(str=="\0" || left>right){
return false;
}
}
int addCharMain(string str,int left,int right){
//终止条件
if(left>right){
return 0;
}
//要添加
if(str[left]==str[right] && left!=right){
return addCharMain(str,left+1,right-1);
}else{
//往左边加
int leftValue=addCharMain(str,left,right-1);
//往右边加
int rightValue=addCharMain(str,left+1,right);
return (leftValue < rightValue)? leftValue+1 : rightValue+1;
}
}
int main() {
addChar("12312",0,4);
return 0;
}
上述算法并非最简,考虑到会有重复计算,所以肯定有效率更高的解法。
思想:
1.添加字符,不要想着添加到中间!添加到首尾也是添加1个,添加到中间也是一个,当然是考虑添加到首尾,把字符串范围逐渐缩小。
2.考虑到可以分首尾,就要想到递归首尾的解法,类似考虑一种不顾效率的分治法。然后发现可能会有重复计算,于是便顺理成章想到用一个数组记录计算过的值。通常记录过程的算法,都与动态规划相关,for和递归都能解决。