字符串 9. 回文数 409. 最长回文串 647. 回文子串 5. 最长回文子串

9. 回文数

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

示例:

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

示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

思路1:栈

将整数转为字符串,根据字符串长度为奇数还是偶数分两种情况讨论:
若为偶数,则先通过遍历将前一半字符入栈,再继续遍历,一边将栈中元素出栈,一边判断当前值是否与出栈元素相等,若不相等,直接返回False。
若为奇数,则先通过遍历将前一半字符入栈,再继续遍历时需要加1,跳过中间元素,然后一边将栈中元素出栈,一边判断当前值是否与出栈元素相等,若不相等,直接返回False。

代码实现1:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        stack = []
        s = str(x)
        # 字符串长度为偶数
        if len(s) % 2 == 0:
            half = len(s) // 2
            for i in range(half):
                stack.append(s[i])
            while stack:
                if stack.pop() != s[half]:
                    return False
                half += 1
        # 字符串长度为奇数
        elif len(s) % 2 != 0:
            half = len(s) // 2
            for i in range(half):
                stack.append(s[i])
            while stack:
                if stack.pop() != s[half+1]:  # 加1,跳过中间元素
                    return False
                half += 1

        return True

思路2:双端队列(复杂度: O ( n 2 ) O(n^2)

将整数转为字符串,再转为列表,前后同时pop并比较,若不同,返回False。

代码实现2:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        deque = list(str(x))
        while len(deque) > 1:
            if deque.pop(0) != deque.pop():
                return False
        return True

思路3:双指针(复杂度: O ( n ) O(n)

将整数转为字符串,两个指针一个指头一个指尾,向中间靠拢,若发现值不同,返回False。

代码实现3:

class Solution:
    def isPalindrome(self, x):
        s = str(x)
        j = -1
        for i in range(len(s) // 2):
            if s[i] != s[j]:
                return False
            j -= 1
        return True

思路4:利用python自由特性(复杂度: O ( n ) O(n)

将整数转为字符串,使用字符串翻转,判断翻转后的字符串是否与原字符串相等。

代码实现4:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        return True if str(x)==str(x)[::-1] else False

思路5(提高):不转字符串(复杂度: O ( n ) O(n)

反转后面一半的整数,判断与前一半是否相等

定义reverse_x=0用于记录翻转的后半部分。

  1. 若x=1221:
    当x>reverse_x时,执行以下操作:
    x对10取余数,得到1,再将x除以10取整,
    x=122,reverse_x = 0 * 10 + 1 = 1
    x对10取余数,得到2,再将x除以10取整,
    x=12,reverse_x = 1 * 10 + 2 = 12
    此时x不再大于reverse_x,完成后半部分的翻转,判断二者是否相等。
  2. 若x=12321:
    当x>reverse_x时,执行以下操作:
    x对10取余数,得到1,再将x除以10取整,
    x=1232,reverse_x = 0 * 10 + 1 = 1
    x对10取余数,得到2,再将x除以10取整,
    x=123,reverse_x = 1 * 10 + 2 = 12
    x对10取余数,得到3,再将x除以10取整,
    x=12,reverse_x = 12 * 10 + 3 = 123
    此时x不再大于reverse_x,完成后半部分的翻转,将reverse_x//10后判断二者是否相等。
  • 注意:" / " 表示浮点数除法,返回浮点结果;" // " 表示整数除法。

代码实现5:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0 or (x != 0 and x % 10 == 0):
            return False
        elif x == 0:
            return True
        else:
            reverse_x = 0
            while x > reverse_x:
                remainder = x % 10
                reverse_x = reverse_x * 10 + remainder
                x = x // 10
            # 当x的位数为奇数时, 只要满足 reverse_x//10 == x 即可
            if reverse_x == x or reverse_x // 10 == x:
                return True
            else:
                return False

思路6:整数翻转

代码实现:

class Solution:
    def isPalindrome(self, x):
        if x < 0:
            return False
        n = x
        ans = 0
        while n != 0:
            j = n % 10
            n //= 10
            ans = ans * 10 + j
        return ans == x

409. 最长回文串

  • 给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
    在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。

示例:

输入: "abccccdd"

输出: 7

解释: 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

思路:

  • 获取字符串中每个字母出现的次数:
    若都是偶数,则可以回文串的长度就是原始字符串长度;
    若只有一个字母是奇数个,则可以将其置于中间,即回文串的长度依然为原始字符串长度;
    若不止一个字母为奇数个,则每多一个,就要减一个字母,使其变为偶数。

代码实现:

class Solution:
    def longestPalindrome(self, s: str) -> int:
        s_set = set(s)
        dlt = 0  # 要删掉的数目
        flag = False  # 如果字符串的数目出现奇数,就记录下来
        for i in s_set:
            # 只要字符串中有一个字符为奇数个,则要删除的数目就多一个
            if s.count(i) % 2 != 0:
                dlt += 1
                flag = True

        if flag:
            # 字符串中出现几次奇数字符,就减几,再加上可以放在中间的一个字符
            ret = len(s) - dlt + 1
        else:
            # 说明字符串中每个字符的个数全是偶数,直接返回原长度
            ret = len(s)
        return ret

647. 回文子串

  • 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
    具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

示例:

示例 1:
输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".

示例 2:
输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

思路:动态规划——从中心往两侧延伸

如图,对于长度为N的字符串,有2N-1个位置可能作为回文串的中心位置,即字母和字母之间。
在这里插入图片描述
对于每个可能的回文串中心位置,尽可能扩大它的回文区间 [left, right]。当 left >= 0 and right < N and S[left] == S[right] 时,扩大区间。此时回文区间表示的回文串为 S[left], S[left+1], …, S[right]。

在每一个中心位置向外延伸:

  1. 中心位置在字母处的,应记录当前字母为子串;
    如对于2号位,应判断s[1] == s[1];对于8号位,应判断s[4] == s[4]。
  2. 中心文字在字母间的,应判断左右两个字母是否可构成回文串;
    如对于3号位,应判断s[1] == s[2];对于9号位,应判断s[4] == s[5]。

即 left = center // 2,right = left + center % 2

代码实现:

class Solution:
    def countSubstrings(self, s: str) -> int:
        n = len(s)
        ans = 0

        for center in range(2 * n - 1):
            left = center // 2
            right = left + center % 2
            while left >= 0 and right < n and s[left] == s[right]:
                ans += 1
                left -= 1
                right += 1
        
        return ans

5. 最长回文子串

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

示例:

示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:
输入: "cbbd"
输出: "bb"

思路:动态规划

  1. 先找出所有回文子串,在找的过程中使用length变量记录子串的长度,每找到一个更长的子串,就更新length,并记录下标,最后通过最长子串的下标返回最长子串。

代码实现:

class Solution:
    def longestPalindrome(self, s: str) -> str:
    	# 如果字符串为空,直接返回
        if s == '':
            return s
        
        n = len(s)
        # 记录最长子串的长度,最短为一个字符
        length = 1
        # 使用字典来存储最长串的左右下标
        dic = {}
        
        # 寻找所有子串
        for center in range(2 * n - 1):
            left = center // 2
            right = left + center % 2
            while left >= 0 and right < n and s[left] == s[right]:
                left -= 1
                right += 1

			# 在不满足循环条件退出时,left和right已经发生延长,如0位置,left = -1,right = 1 长度应为right - left - 1 = 1
            if right - left - 1 > length:
            	# 记录左右下标位置,应为延长前的索引值
                dic['left'] = left + 1
                dic['right'] = right - 1
                length = right - left - 1
                
		# 若长度为1,返回第一个字符即可
        if length == 1:
            return s[0]
        return s[dic['left']:dic['right']+1]
发布了51 篇原创文章 · 获赞 4 · 访问量 3512

猜你喜欢

转载自blog.csdn.net/yhhuang17/article/details/104930404