算法:回文相关题目

问题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和递归都能解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值