LintCode刷题——分割回文串Ⅱ(序列型动态规划)

题目描述:

给定字符串 s, 需要将它分割成一些子串, 使得每个子串都是回文串.

最少需要分割几次?

样例

样例 1:

输入:
"a"
输出:
0
解释: 
"a" 本身就是回文串, 无需分割

样例 2:

输入:
"aab"
输出:
1
解释:"aab" 分割一次, 得到 "aa""b", 它们都是回文串.


思路:

这里我们最主要的就是如何判断出指定区间的字符串为回文串,我们可以从前往后,以每一个字符为基石,让其往两边伸展,然后考虑奇偶性,因为一个回文串的长度要么是奇数,要么是偶数,就这两种情况,所以我们就可以定住每一个中间字符,向外扩展,判断这个字符串中哪些区间是回文串,哪些不是。并用一个二维的布尔类型数组记录每一个区间是否为回文串,接下来考虑最后一步就很容易了,我们知道最后一步一定是从第j个位置分割,将第j + 1个字符到最后一个字符划分为一个回文串,当我们考虑前i个字符的串是否为回文串时,我们就需要从第一个字符遍历到第i个字符,从中找到最少分割次数并更新。这样一来我们就把考虑前i个字符的串最少分割几次,转变为前j个字符的串最少分割几次。

转移方程:f[i] = min{f[i], f[j] + 1}

 

AC代码:

复制代码
 1 public class Solution {
 2     /**
 3      * @param s: A string
 4      * @return: An integer
 5      */
 6     public int minCut(String s) {
 7         // write your code here
 8         if (s == null || s.length() == 0) {
 9             return 0;
10         }
11 
12         char[] c = s.toCharArray();
13         int n = c.length;
14 
15         boolean[][] isPalins = new boolean[n][n];
16 
17         // initialization
18         for (int i = 0; i < n; i++) {
19             for (int j = 0; j < n; j++) {
20                 isPalins[i][j] = false;
21             }
22         }
23 
24         // 定基准
25         for (int t = 0; t < n; t++) {
26             int i, j;
27             // 默认一个字符也是回文串
28             i = t;
29             j = t;
30 
31             // odd
32             while (i >= 0 && j < n && c[i] == c[j]) {
33                 isPalins[i][j] = true;
34                 i--;
35                 j++;
36             }
37 
38             i = t;
39             j = t + 1;
40             // even
41             while (i >= 0 && j < n && c[i] == c[j]) {
42                 isPalins[i][j] = true;
43                 i--;
44                 j++;
45             }
46         }
47 
48         // 定义状态:dp[i] 代表前i个字符中回文串的个数
49         int[] dp = new int[n + 1];
50 
51         // 初始化
52         dp[0] = 0;
53 
54         for (int i = 1; i <= n; i++) {
55             // 因为这里是取最小值,所以一开始要设为无穷大
56             // 任意一个字符串(空串除外)都能化成若干个回文串(因为单个字符就是一个回文串),所以一定可以分割出来,即这里设置为无穷大也就没啥问题
57             dp[i] = Integer.MAX_VALUE;
58             // 从第一个字符一直遍历到第i个字符。挨个判断,取最小值
59             for (int j = 0; j < i; j++) {
60                 if (isPalins[j][i - 1]) {
61                     // is Palin
62                     dp[i] = Math.min(dp[i], dp[j] + 1);
63                 }
64             }
65         }
66 
67         // 别忘了本题是让我们求最小需要分割几次,所有最后要-1
68         return dp[n] - 1;
69     }
70 }
复制代码

 

posted @   没有你哪有我  阅读(96)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
点击右上角即可分享
微信分享提示