最长回文子串
题目
给你一个字符串 s
,找到 s
中最长的回文子串。
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
分析
暴力求解很容易想到,遍历所有可能的子串然后从中找到最长的一个回文子串。
可以使用动态规划的方法进行优化。这里顺便复习一下动态规划:
所谓动态规划,核心思想就是利用之前算过的结果快速推算新的计算结果。通常的实现方法是把之前算的结果存在数组中。
分析问题时用递归的思想去考虑,类似于数学归纳法。若要知道当前问题的答案,只需要知道他上一步,再处理一步即可。
最后通过递归终止条件,也就是最简单的情况结束,这就是所谓的动态规划的状态转移方程和边界条件。
所以本题中,可以通过数学归纳的思想,找到动态规划的求解方法。首先,单个字符,两个相连的相同字符都是回文串。接下来,对于其他回文串,如果两头各加一个相同字符,得到的新串是回文串。所以动态规划的状态转移方程可以写为:
P(i,j)=P(i+1,j−1)∧(S**i==S**j)
通过一个二维数组 dp[][] , dp[i][j] = True 就表示从第i字符到第j字符之间的子串是回文串。这样就可以在后续判断更长的子串是不是回文串的时候查询,来利用已经计算好的结果来节约时间。
代码示例:
class Solution:
def longestPalindrome(self, s: str) -> str:
total = len(s)
dp = [[False] * total for _ in range(total)]
ans=""
noPalindrome=True
for l in range(total):
noPalindrome=True
for i in range(total):
j = i + l
if j >= total:
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = s[i] == s[j]
else:
dp[i][j] = dp[i + 1][j - 1] and s[i] == s[j]
if dp[i][j] and noPalindrome:
ans=s[i:j+1]
noPalindrome=False
return ans
算法分析:时间复杂度 O(n^2) 空间复杂度 O(n^2)
另一种方法是中心扩展法,也就是以每个字符为中心,向外寻找最长的回文串。空间复杂度为O(1)
整数反转
题目
给你一个 32 位的有符号整数 x ,返回 x 中每位上的数字反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号),只能存取32位的整数。
输入:x = -123
输出:-321
分析
对整数进行反转,本题不建议通过字符串来做,会徒增很多无用功导致效率变慢,而且在判断溢出上也较为麻烦。
反转整数,其实就是每次取出原数的最后一位,从后面压入新数中。数学上就是每次把前一次的结果乘10再加上新的一位。判断溢出时,需要在计算下一次的结果前进行预测。
另外还需要考虑到负数的情况,先将符号记录下来按照正数处理,然后给结果加上符号。还要注意正负数判断溢出的条件差1,要进行区分。
示例代码:
class Solution:
def reverse(self, x: int) -> int:
res = 0
up = 2 ** 31 - 1
down = -2 ** 31
flag = x < 0
if flag:
x = -x
while x != 0:
num = x % 10
x //= 10
if not flag and (res > up // 10 or (res == up // 10 and num > 7)):
return 0
if flag and (res > up // 10 or (res == up // 10 and num > 8)):
return 0
res = res * 10 + num
if flag:
res = -res
return res
判断溢出总结
这个题涉及到了对溢出的判断,因此顺便总结一下对整数大数溢出的几种判断方法。
两数相加
符号相反的两个数相加不会溢出;符号相同的两数,如果相加的结果符号变化了,则表示溢出了。
两数相乘
不能通过符号来判断是否溢出。但是可以用结果做逆运算,把结果除以其中一个乘数,如果不能得到另一个乘数,则表示溢出了。
其实上面的两数相加也可以用类似的方法判断,但是符号判断已经足够便利。
对一个数固定的操作
上面两种溢出判断都建立在溢出后不能得到正确结果的前提上,而且要先计算结果才知道是不是错了。但是也可以预先对操作结果进行判断。
例如将一个数乘10。最好可以在溢出前就对这个数需要满足的条件进行判断。如果这个数本身已经大于 MaxInt/10 那么它乘10的结果就会溢出。