LeetCode刷题之路(第二天)

5.最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例 1:

输入: “babad”
输出: “bab”
注意: "aba"也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”

这个算法中如果使用暴力法去求解,很明显需要选择所有子字符串的位置,并检查它是不是回文,子字符串有n(n-1)/2的情况,验证每个字符串需要O(n)的时间,故运行时间复杂度为O(n3)。那么如何提高呢?可以使用动态规划的思路,考虑“ababa”如果已知了“bab”是回文,且他两端的字母相同,那么这个字符串也一定是回文:在这里插入图片描述
这是一个很直观的动态规划解法,首先初始化一字母和二字母的回文,然后找出所有的三字母回文。但是这样的算法的空间复杂度为O(n2),时间复杂度也为O(n2)。算法如下:

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.length();
        vector<vector<bool>> table(s.length(), vector<bool>(s.length(), false));
        int longestbegin = 0;
        int maxlen = 1;
        
        for(int i = 0;i < n;i++){
            table[i][i] = true;
            if(i != n && s[i] == s[i+1]){
                table[i][i+1] = true;
                longestbegin = i;
                maxlen = 2;
            }
        }
        for(int len = 3;len <= n; len++){
            for(int i = 0;i < n-len+1;i++){
                int j = i + len -1;
                if(s[i] == s[j] && table[i+1][j-1]){
                    table[i][j] = true;
                    longestbegin = i;
                    maxlen = len;
                }
            }
        }
        return s.substr(longestbegin, maxlen);
    }
};

第二种思路是使用中心拓展法,主要就是把给定字符串的每个字母当做中心,向两边查找最大的回文子串,注意奇数和偶数的情况。其空间复杂度为O(1),时间复杂度为O(n2)。

class Solution {
private:
    int left = 0, maxlen = 1;
public:
    
   void findMaxPalindrome(string s, int i, int j){
    while(i >= 0 && j < s.length() && s[i] == s[j]){
        i--; j++;
    }
    if (maxlen < j-i-1){
        left = i+1;
        maxlen = j-i-1;   //获得最大长度
    }
   }
    string longestPalindrome(string s) {
        if((s == "") || s.length() < 2)
            return s;    //极端情况
        for(int i = 0;i < s.length()-1;i++){
            // 两种情况:中间是bab,中间bb
            findMaxPalindrome(s, i, i);
            findMaxPalindrome(s, i, i+1);
        }
        return s.substr(left, maxlen);
    }
};

6.Z字形变换

将字符串 “PAYPALISHIRING” 以Z字形排列成给定的行数:

P       A         H        N
A   P   L    S    I    I   G
Y       I         R

之后从左往右,逐行读取字符:“PAHNAPLSIIGYIR”

实现一个将字符串进行指定行数变换的函数:

string convert(string s, int numRows); 示例 1:

输入: s = “PAYPALISHIRING”, numRows = 3
输出: “PAHNAPLSIIGYIR” 示例 2:

输入: s = “PAYPALISHIRING”, numRows = 4
输出: “PINALSIGYAHRPI”

其实Z字形就相当于波浪线这样来走的,所以可以根据这个规律去思考算法的结构,总的来说就是从第零行开始向下走,到了第n行然后向上走,最后按照每行的元素进行重新排列。

class Solution {
public:
    string convert(string s, int nRows) {
        int step = 1, row = 0;  //1是向下,-1是向上
        vector<string> res(nRows, "");
        string result = "";
        if(nRows < 2) return s;
        for(int i = 0;i < s.length();i++){
            res[row] += s[i];    //strIng类型的优势
            if(row == nRows-1)
                step = -1;
            else if(row == 0)
                step = 1;
            row = row + step;
        }
        for(int i = 0;i < nRows;i++){
            result += res[i];
        }
        return result;
    }
};

7. 翻转整数

给定一个 32 位有符号整数,将整数中的数字进行反转。

示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21

注意:
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。根据这个假设,如果反转后的整数溢出,则返回 0。

class Solution {
public:
    int reverse(int x)
    {
       long long res = 0;
       while(x!=0)
       {
           res = res*10+x%10;
           x/=10;
           if(res >= INT_MAX || res <= INT_MIN)
               return 0;
       }
        return res;
    }
};

8. 字符串转整数 (atoi)

实现 atoi,将字符串转为整数。

该函数首先根据需要丢弃任意多的空格字符,直到找到第一个非空格字符为止。如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即为整数的值。如果第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

字符串可以在形成整数的字符后面包括多余的字符,这些字符可以被忽略,它们对于函数没有影响。

当字符串中的第一个非空字符序列不是个有效的整数;或字符串为空;或字符串仅包含空白字符时,则不进行转换。

若函数不能执行有效的转换,返回 0。

说明:
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。如果数值超过可表示的范围,则返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

class Solution {
public:
    int atoi(const char *str) {
        int k = 0;
		long ans = 0L;   //建议设为long型,为了判断溢出
		bool sig = false;   //默认正数
        string s(str);
		for (int i = 0; i < s.length(); i++) {
			if (s[i] != ' ') {
				k = i;
				break;
			}
		}
		if (s[k] == '-' || s[k] == '+') {
			sig = s[k] == '-' ? true : false; 
            k++;
		}
		while (s[k] >= '0' && s[k] <= '9') {
			ans = ans * 10 + (s[k] - '0');
			k++;
            if ( (sig ? -1 : 1) * ans >= INT_MAX)  return INT_MAX;  //在这里进行溢出判断
		    if ( (sig ? -1 : 1) * ans <= INT_MIN)  return INT_MIN;
		}
		ans =  (sig ? -1 : 1) * ans;
		return ans;
    }
};

9. 回文数

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

示例 1:
输入: 121
输出: true

class Solution {
public:
    bool isPalindrome(int x) {
        int reverse = 0;
        if ((x < 0 || x%10 == 0) && (x != 0)) return false;  //去除特例
        while(x > reverse){     //当商小于reverse时候,说明到一半了
            reverse = reverse*10 + x % 10;
            x = x / 10;
        }
        return (reverse/10 == x || reverse == x);   //当奇个数时,reverse的最后一位为中间数
    }
};

声明

以上代码均参考于牛客网并在牛客网测试成功。参考了各位大佬的思路整理而成,希望大家一起学习~

猜你喜欢

转载自blog.csdn.net/weixin_41576121/article/details/82761852