【问题标题】:Number of palindromic subsequences of length 5长度为 5 的回文子序列的数量
【发布时间】:2022-11-26 23:58:25
【问题描述】:

给定一个字符串s,返回长度为 5 的回文子序列的数量。

测试用例 1:

input : "abcdba"
Output : 2
"abcba" and "abdba"

测试用例 2:

input : "aabccba"
Output : 4
"abcba" , "abcba" , "abcba" , "abcba"

字符串的最大长度:700

我的 TLE 方法:O(2^n)

https://www.online-java.com/5YegWkAVad

任何输入都非常感谢......

【问题讨论】:

  • 好的,您有问题链接可以在回答之前测试我的解决方案吗?
  • 嗨@nice_dev,我找到了here problem 2
  • 是的,应该是21。我会修改并通知您。
  • 哦,好吧,也许我们可以假设输入将以输出适合长数据类型的方式提供
  • 从链接的问题陈述:“保证对于给定的测试用例,答案总是适合带符号的 32 位整数类型。”

标签: string algorithm


【解决方案1】:
  • 每当有 2 个字符匹配时,我们只需要找出在这 2 个字符之间可能有多少个长度为 3 的回文。

例如:

a bcbc a
^      ^
|_ _ _ |

在上面的例子中,你可以找到2个长度为3的回文,即bcbcbc。因此,我们可以将长度为5的回文序列构造为abcbaacbca。因此,答案是2

  • 如果我们在第一次执行时不缓存结果,那么计算每个子串可能有多少个长度为 3 的回文可能会非常耗时。因此,缓存这些结果并将它们重新用于由其他 2 个字符匹配生成的查询。 (a.k.a dynamic programming)

  • 这样,解决方案就变成了二次方O(n^2)时间,其中n是字符串的长度。

片段:

private static long solve(String s){
  long ans = 0;
  int len = s.length();
  long[][] dp = new long[len][len];
  
  /* compute how many palindromes of length 3 are possible for every 2 characters match */
  for(int i = len - 2;i >= 0; --i){
    for(int j = i + 2; j < len; ++j){
      dp[i][j] = dp[i][j-1] + (dp[i + 1][j] == dp[i + 1][j-1] ? 0 : dp[i + 1][j] - dp[i + 1][j - 1]);
      if(s.charAt(i) == s.charAt(j)){
        dp[i][j] += j - i - 1;
      }
    }
  }
  
  /* re-use the above data to calculate for palindromes of length 5*/ 
  for(int i = 0; i < len; ++i){
    for(int j = i + 4; j < len; ++j){
      if(s.charAt(i) == s.charAt(j)){
        ans += dp[i + 1][j - 1];
      }
    }
  }
  
  //for(int i=0;i<len;++i) System.out.println(Arrays.toString(dp[i]));
  
  return ans;
} 

Online Demo

更新:

 dp[i][j] = dp[i][j-1] + (dp[i + 1][j] == dp[i + 1][j-1] ? 0 : dp[i + 1][j] - dp[i + 1][j - 1]);

上面一行基本上是这个意思,

  • 对于任何子字符串,比如bcbcb,匹配第一个和最后一个b, 总共3个回文长度可以相加
    • bcbc 的可能总数。
    • cbcb 的可能总数。
    • bcbcb(在if条件下为(j - i - 1))的可能总数。
  • dp[i][j] 手头的当前子字符串。
  • dp[i][j-1] - 添加前面的长度为 3 的子串计数。在此示例中,bcbc
  • dp[i + 1][j],添加以当前索引结尾的子字符串,不包括第一个字符。 (在这里,cbcb)。
  • dp[i + 1][j] == dp[i + 1][j-1] ? 0 : dp[i + 1][j] - dp[i + 1][j - 1] 这基本上是为了避免对内部子字符串进行重复计数,并且仅在计数存在差异时才添加它们。

【讨论】:

  • 很好的直觉,当找到长度为 3 的回文时,你能解释一下这部分吗dp[i][j] = dp[i][j-1] + (dp[i + 1][j] == dp[i + 1][j-1] ? 0 : dp[i + 1][j] - dp[i + 1][j - 1]);
  • @Turtle 很高兴提供帮助并尝试这样做。我已经为我的答案添加了更新。希望这次我的解释更具可读性。
  • 在使用 dp 表和讨论它的长更新行之前,我会写下它的确切定义方法.在编写实际代码之前,这通常是我真正写下的第一件事(在纸上或作为代码注释)。类似于 dp[i][j] = number of length-3 palindromes in s[i:j]s[i:j] 是 Python 符号,不知道 Java 的约定。)
【解决方案2】:

我认为这篇文章会有所帮助,通过存储两位数对的数量,它的时间复杂度为 O(n)。

看到这个: Number of palindromes of length 5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-13
    • 2018-11-15
    • 2013-04-30
    • 2012-11-23
    • 2012-10-05
    • 2017-02-25
    • 1970-01-01
    • 2018-02-19
    相关资源
    最近更新 更多