Count Different Palindromic Subsequences

Given a string S, find the number of different non-empty palindromic subsequences in S, and return that number modulo 10^9 + 7.

A subsequence of a string S is obtained by deleting 0 or more characters from S.

A sequence is palindromic if it is equal to the sequence reversed.

Two sequences A_1, A_2, ... and B_1, B_2, ... are different if there is some i for which A_i != B_i.

Example 1:

Input: 
S = 'bccb'
Output: 6
Explanation: 
The 6 different non-empty palindromic subsequences are 'b', 'c', 'bb', 'cc', 'bcb', 'bccb'.
Note that 'bcb' is counted only once, even though it occurs twice.

 

Example 2:

Input: 
S = 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba'
Output: 104860361
Explanation: 
There are 3104860382 different non-empty palindromic subsequences, which is 104860361 modulo 10^9 + 7.

 1 class Solution {
 2     public int countPalindromicSubsequences(String S) {
 3         Map<String, Set<String>> _seqMap = new HashMap<>();
 4         return findPalindromesHelper(S, _seqMap).size();
 5     }
 6 
 7     private Set<String> findPalindromesHelper(String s, Map<String, Set<String>> _seqMap) {
 8         Set<String> result = _seqMap.get(s);
 9         if (result != null) {
10             return result;
11         }
12         int len = s.length();
13         result = new HashSet<String>();
14         if (len < 1) {
15             return result;
16         }
17         if (len == 1) {
18             result.add(s);
19             return result;
20         }
21         result.addAll(findPalindromesHelper(s.substring(0, len - 1), _seqMap));
22         result.addAll(findPalindromesHelper(s.substring(1, len), _seqMap));
23         if (s.charAt(0) == s.charAt(len - 1)) {
24             Set<String> subSet = findPalindromesHelper(s.substring(1, len - 1), _seqMap);
25             String head = s.substring(0, 1);
26             for (String s1 : subSet) {
27                 result.add(head + s1 + head);
28             }
29             result.add(head + head);
30         }
31         _seqMap.put(s, result);
32         return result;
33     }
34 }
 1 class Solution {
 2     public int countPalindromicSubsequences(String s) {
 3         int len = s.length();
 4         int[][] dp = new int[len][len];
 5 
 6         char[] chs = s.toCharArray();
 7         for (int i = 0; i < len; i++) {
 8             dp[i][i] = 1; // Consider the test case "a", "b" "c"...
 9         }
10 
11         for (int distance = 1; distance < len; distance++) {
12             for (int i = 0; i < len - distance; i++) {
13                 int j = i + distance;
14                 if (chs[i] == chs[j]) {
15                     int low = i + 1, high = j - 1;
16                     while (low <= high && chs[low] != chs[j]) {
17                         low++;
18                     }
19                     while (low <= high && chs[high] != chs[j]) {
20                         high--;
21                     }
22                     if (low > high) {
23                         /*
24                          * consider the string from i to j is "a...a" "a...a"... where there is no
25                          * character 'a' inside the leftmost and rightmost 'a'
26                          *
27                          * eg: "aba" while i = 0 and j = 2: dp[1][1] = 1 records the palindrome{"b"},
28                          * the reason why dp[i + 1][j - 1] * 2 counted is that we count dp[i + 1][j - 1]
29                          * one time as {"b"}, and additional time as {"aba"}. The reason why 2 counted
30                          * is that we also count {"a", "aa"}. So totally dp[i][j] record the palindrome:
31                          * {"a", "b", "aa", "aba"}.
32                          */
33                         dp[i][j] = dp[i + 1][j - 1] * 2 + 2;
34                     } else if (low == high) {
35                         /*
36                          * consider the string from i to j is "a...a...a" where there is only one
37                          * character 'a' inside the leftmost and rightmost 'a'
38                          *
39                          * eg: "aaa" while i = 0 and j = 2: the dp[i + 1][j - 1] records the palindrome
40                          * {"a"}. the reason why dp[i + 1][j - 1] * 2 counted is that we count dp[i +
41                          * 1][j - 1] one time as {"a"}, and additional time as {"aaa"}. the reason why 1
42                          * counted is that we also count {"aa"} that the first 'a' come from index i and
43                          * the second come from index j. So totally dp[i][j] records {"a", "aa", "aaa"}
44                          */
45                         dp[i][j] = dp[i + 1][j - 1] * 2 + 1;
46                     } else {
47                         /*
48                          * consider the string from i to j is "a...a...a... a" where there are at least
49                          * two character 'a' close to leftmost and rightmost 'a'
50                          *
51                          * eg: "aacaa" while i = 0 and j = 4: the dp[i + 1][j - 1] records the
52                          * palindrome {"a", "c", "aa", "aca"}. the reason why dp[i + 1][j - 1] * 2
53                          * counted is that we count dp[i + 1][j - 1] one time as {"a", "c", "aa",
54                          * "aca"}, and additional time as {"aaa", "aca", "aaaa", "aacaa"}. Now there is
55                          * duplicate : {"aca"}, which is removed by deduce dp[low + 1][high - 1]. So
56                          * totally dp[i][j] record {"a", "c", "aa", "aca", "aaa", "aaaa", "aacaa"}
57                          */
58                         dp[i][j] = dp[i + 1][j - 1] * 2 - dp[low + 1][high - 1];
59                     }
60                 } else {
61                     dp[i][j] = dp[i][j - 1] + dp[i + 1][j] - dp[i + 1][j - 1]; // s.charAt(i) != s.charAt(j)
62                 }
63                 dp[i][j] = dp[i][j] < 0 ? dp[i][j] + 1000000007 : dp[i][j] % 1000000007;
64             }
65         }
66         return dp[0][len - 1];
67     }
68 }

 

Guess you like

Origin www.cnblogs.com/beiyeqingteng/p/11206410.html