女朋友跟我说“爱你爱你”,我首先想到的竟是“回文数”!_字符串

 

今天是2020年02月02日,传说中千年一遇的完全对称日。同时,2020又谐音“爱你爱你”。在如此特殊的日子里,你难道不想干点什么吗?当然,专家建议疫情期间少出门。

 

当女朋友早上兴冲冲地跟我说 “今天是20200202” 的时候,我的第一反映竟然是!

 

这不是个回文数吗?然后脑子里开始快速闪过一段又一段讳莫如深的代码...

 

emmmm......别问我为什么能有女朋友!

 

 

01

回文数

 

Leetcode 09 回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。比如20200202就是一个回文数。

 

判断回文数有三种解法:

 

1 一般解法

将整数转为字符串,然后将字符串分割为数组,通过循环数组的一半长度进行判

断对应的元素是否相等。

(代码略)

 

2 除法操作

通过取整和取余操作获得整数中对应的数字进行比较。

 

举个例子:20200202 这个数字。通过计算 20200202 / 1000000, 得首位2通过计算 20200202 % 10000000, 可得末位 2将首位和末位进行比较,再将第2位0和倒数第2位0取出来继续比较。代码:
  •  
class Solution {public:    bool isPalindrome(int x) {        //边界判断        if (x < 0) return false;        int div = 1;        //        while (x / div >= 10) div *= 10;        while (x > 0) {            int left = x / div;            int right = x % 10;            if (left != right) return false;            x = (x % div) / 10;            div /= 100;        }        return true;    }};

 

3 对折解法

取出后半段数字进行翻转,看与前半段数字是否相同。

  •  
class Solution {public:    bool isPalindrome(int x) {        if (x < 0 || (x % 10 == 0 && x != 0)) return false;        int revertedNumber = 0;        while (x > revertedNumber) {            revertedNumber = revertedNumber * 10 + x % 10;            x /= 10;        }        return x == revertedNumber || x == revertedNumber / 10;    }};

 

02

最长回文子串

 

Leetcode 5 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。比如"babad"中最长的回文字串是bab或者aba;比如“cbbd”中最长的回文字串是bb。

 

求最长回文字串的解法有很多,这里主要介绍四种。

 

1 暴力解法

列举所有的子串,判断是否为回文串,保存最长的回文串。

 

时间复杂度:两层 for 循环 O(n²)O(n²),for 循环里边判断是否为回文 O(n)O(n),所以时间复杂度为O(n³)O(n³)。这个复杂度太吓人了,写出来面试官可能就会溜了。

空间复杂度:O(1)O(1),常数个变量。

(代码略)

 

2 动态规划

重点是能够列举初始状态:

 

dp[i][i]=1; //单个字符是回文串dp[i][i+1]=1 如果 s[i]=s[i+1]; //连续两个相同字符是回文串

代码:

  •  
class Solution {public:    string longestPalindrome(string s) {        int len=s.size();        if(len==0||len==1)            return s;        int start=0;//回文串起始位置        int max=1;//回文串最大长度        vector<vector<int>>  dp(len,vector<int>(len));//定义二维动态数组        for(int i=0;i<len;i++)//初始化状态        {            dp[i][i]=1;            if(i<len-1&&s[i]==s[i+1])            {                dp[i][i+1]=1;                max=2;                start=i;            }        }        for(int l=3;l<=len;l++)//l表示检索的子串长度,等于3表示先检索长度为3的子串        {            for(int i=0;i+l-1<len;i++)            {                int j=l+i-1;//终止字符位置                if(s[i]==s[j]&&dp[i+1][j-1]==1)//状态转移                {                    dp[i][j]=1;                    start=i;                    max=l;                }            }        }        return s.substr(start,max);//获取最长回文子串    }};

 

3 中心扩展法

回文中心的两侧互为镜像。因此,回文可以从他的中心展开,并且只有 2n-1 个这样的中心(一个元素为中心的情况有 n 个,两个元素为中心的情况有 n-1 个)

 

代码:

  •  
class Solution {public:    string longestPalindrome(string s) {        int len=s.size();        if(len==0||len==1)            return s;        int start=0;//记录回文子串起始位置        int end=0;//记录回文子串终止位置        int mlen=0;//记录最大回文子串的长度        for(int i=0;i<len;i++)        {            int len1=expendaroundcenter(s,i,i);//一个元素为中心            int len2=expendaroundcenter(s,i,i+1);//两个元素为中心            mlen=max(max(len1,len2),mlen);            if(mlen>end-start+1)            {                start=i-(mlen-1)/2;                end=i+mlen/2;            }        }        return s.substr(start,mlen);        //该函数的意思是获取从start开始长度为mlen长度的字符串    }private:    int expendaroundcenter(string s,int left,int right)    //计算以left和right为中心的回文串长度    {        int L=left;        int R=right;        while(L>=0 && R<s.length() && s[R]==s[L])        {            L--;            R++;        }        return R-L-1;    }};

 

4 Manacher(马拉车) 算法

Manacher 算法本质上还是中心扩散法,只不过它使用了类似 KMP 算法的技巧,充分挖掘了已经进行回文判定的子串的特点,在遍历的过程中,记录了已经遍历过的子串的信息,也是典型的以空间换时间思想的体现。

 

该算法的推理过程比较复杂,下次可以再写一篇文章来详细介绍。这里只是甩出代码。

 

  •  
class Solution {private:    int centerSpread(string s, int center) {        int len = s.size();        int i = center - 1;        int j = center + 1;        int step = 0;        while (i >= 0 && j < len && s[i] == s[j]) {            i--;            j++;            step++;        }        return step;    }public:    string longestPalindrome(string s) {        // 特判        int size = s.size();        if (size < 2) {            return s;        }        // 得到预处理字符串        string str = "#";        for (int i = 0; i < s.size(); ++i) {            str += s[i];            str += "#";        }        int sSize = 2 * size + 1;        int maxLen = 1;
int start = 0; for (int i = 0; i < sSize; i++) { int curLen = centerSpread(str, i); if (curLen > maxLen) { maxLen = curLen; start = (i - maxLen) / 2; } } return s.substr(start, maxLen); }};

 

 

03

2020爱你爱你

 

思绪从20200202转到回文数再到回文序列判断,已然不能再深入下去了,否则或许会迎来女朋友的公开审问。

 

今年开年实在是有太多让人感慨无奈又忧心忡忡的事情了,好在至少还有今天这么个日子。虽然说不上多重要,但是能够听到最爱的人看似随意而又深情满满的告白,不也是件乐事嘛。

 

当然了,单身的朋友坐等国家分配就好。然后等下一个千年一遇的日子哈。

 

最后希望疫情早日结束!

女朋友跟我说“爱你爱你”,我首先想到的竟是“回文数”!_回文数_02

 

女朋友跟我说“爱你爱你”,我首先想到的竟是“回文数”!_子串_03

扫个关注,有空来看看直男程序员的业余分享。

女朋友跟我说“爱你爱你”,我首先想到的竟是“回文数”!_回文串_04