动态规划

【区间DP、双指针】647. Palindromic Subst

2019-06-06  本文已影响0人  牛奶芝麻

题目描述:

Given a string, your task is to count how many palindromic substrings in this string.

The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.

Example 1:
Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".

Note:

解题思路:

该题计算字符串中有多少个不同的回文子串,注意:具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

首先想到暴力,时间复杂度 O(N^3),pass。

方法1(双指针):

回文串按照长度分为两种:长度为奇数的的回文串(如 'a', 'aba')和长度为偶数的回文串(如 'aa', 'abba')。双指针的做法利用了这个性质,将字符串的每个位置 i 分为两种情况:

对于每个位置 i,累加两种情况下的回文子串个数,最后,再加上字符串的长度就是答案(因为单个字符也是回文串)。

举例:
如 s = "aaaaa", 假设现在遍历到 s[1] = 'a',分两种情况:

每个位置都从长度为 2 和长度为 3 的子串分别计算,向两端扩展,计算偶回文串和奇回文串的个数。

时间复杂度 O(N^2),空间复杂度 O(1)。

Python3 实现:
class Solution:
    # 方法1:双指针,分奇回文串和偶回文串
    def countSubstrings(self, s: str) -> int:
        lens = len(s)
        even = odd = 0
        for i in range(lens):
            even += self.count(s, lens, i, i+1)  # 统计偶回文串个数
            odd += self.count(s, lens, i, i+2)  # 统计奇回文串个数
        return lens + even + odd  # 单个字符也是回文串

    def count(self, s, lens, i, j):
        cnt = 0
        while i >= 0 and j < lens and s[i] == s[j]:
            cnt += 1
            i -= 1
            j += 1
        return cnt

print(Solution().countSubstrings("aaa"))  # 6
print(Solution().countSubstrings("aabba"))  # 8
方法2(动态规划):

动态规划的思想是,dp[i][j] 表示子串 s[i,j] 是不是回文串,初始化为 False。最后,对 dp[lens(s)][len(s)] 所有的 True 求和,就是最后的答案。

接下来找状态转移方程:

当我们要确定 dp[i][j] 是否为 True,需要考虑:(1)dp[i+1][j-1] 是回文串吗?;(2)s[i] == s[j] 吗?

因此,我们得到转移方程:dp[i][j] = True, if dp[i+1][j-1] == True and s[i] == s[j]

举例:
如 s = "abcba", dp[0][4] = True,因为 dp[0+1][4-1] 为 True 且 s[0] == s[4]。

编程时注意点:
1、在进行双循环遍历时,应该按照 (0,0);(1,1)、(0,1);(2,2)、(1,2)、(0,2);(3,3)、(2,3)、(1,3)、(0,3) 的顺序遍历,这样可以保证在计算 dp[i][j] 时 dp[i+1][j-1] 已经计算出来了。
2、对于 s = 'aa' 这种,计算 dp[0][1] 为 True 时,由于 dp[0+1][1-1] 导致 dp[1][0] 无意义,因此对于这种情况,只需要保证 s[0] == s[1] 即可。

Python3 实现:
class Solution:
    # 方法2:dp[i][j] = True, if dp[i+1][j-1] == True and s[i] == s[j]
    def countSubstrings(self, s: str) -> int:
        lens = len(s)
        dp = [[False] * lens for _ in range(lens)]
        for j in range(lens):  # 注意遍历的顺序
            dp[j][j] = True
            for i in range(j-1, -1, -1):   # 注意遍历的顺序
                if i+1 <= j-1 and dp[i+1][j-1] == True and s[i] == s[j]:  
                    dp[i][j] = True
                elif i+1 > j-1 and s[i] == s[j]:
                    dp[i][j] = True
        cnt = 0
        for i in range(lens):
            cnt += sum(dp[i])
        return cnt

print(Solution().countSubstrings("aaaa"))  # 10
print(Solution().countSubstrings("aabbaa"))  # 11
上一篇下一篇

猜你喜欢

热点阅读