Palindrome II
Problem Statement
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab", Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
First we need to give some definitions. Then
Define
- to indicate the minimum number of cuts of the first characters in string , {}.
- Thus, the index of cut is one more than index of s, which means the number of minimum cut of {} will be stored at , or . For simplicity, we use the terminology minimum cut of to indicate minimum cut of {}.
- So the problem can be expressed to compute .
Obviously, the initial should be . Because every node itself is a palindrome. Thus nodes at most need partitions:
1 2 | for ( int i = 0; i < n; ++i) cut[i] = i - 1; |
At first sight, the assignment seems like a garbage value, but later we will explain it's very useful to assign to -1 to complete our problem.
In order to find some intuitions, let's think about the minimum cut of string {} with partitions.
Denote the cut like: {} = {} =
{
{},
{},
{...},
....,
{},
{}
}.
Immediately, we can get
- The node must be in with . And is a palindrome.
- Also, consider the node . We can state that {} is also the minimum cut of string {}.
(Otherwise, we can use {}'s minimum cut {} {} to get {}'s smaller cut, which contradicates to {}'s minimum.)- Based on the above two statements, we also get , which means , or .
- The situation that the whole string {} is palindrome, i.e., {}, and , is also included.
As the deductions above, , which matches the result of our problem.- Point 4 also explains that the initial assignment of cut[0] = -1 is useful and meaningful.
From these insights, we can get that for every minimum partition, let's say node 's minimum cut, there exists some , where , such that
's minimum cut =
{}'s minimum cut
{}, where {} is a palindrome.
Thus, if we test a palindrome {}, it may be the minimum partition's last part . So we may have a chance to update 's minimum cut, i.e. updating cut[q+1] by
1 2 | if (isPalindrome(s, p, q)) cut[q+1] = max(cut[q+1], cut[p]+1) |
As every node 's can only be affected by its previous nodes, we can systematically detect palindrome and then update from the beginning of string s.
1 2 3 4 | for ( int point = 0; point < n; ++point){ //detect palindrome and update cut[i] ... } |
For every node , we consider palindrome centralized at . Of course, there may be two cases of palindrome centralized at :
- [] with odd length .
- [] with even length
We can expand the half length from zero until it reaches the boundary or . And once the expansion of length stops at some length , there won't exist palindrome centralized at with length greater than .
1 2 3 4 5 6 7 | // odd length for ( int halfLength = 0; point-halfLength >= 0 && point+halfLength < n && s[point-halfLength] == s[point+halfLength]) cut[point+halfLength+1] = min(cut[point+halfLength+1], cut[point-halfLength]+1); // even length for ( int halfLength = 1; point-halfLength+1 >= 0 && point+halfLength < n && s[point-halfLength+1] == s[point+halfLength]) cut[point+halfLength+1] = min(cut[point+halfLength+1], cut[point-halfLength+1]+1) |
or if we use denote central point, and denote half length, we can get a piece of simply code:
1 2 3 4 5 6 7 8 9 | for ( int i = 0; i < n; ++i){ //odd length for ( int j = 0; i-j >= 0 && i+j < n && s[i-j] == s[i+j]; ++j) cut[i+j+1] = min(cut[i+j+1], cut[i-j]+1); //even length for ( int j = 1; i-j+1 >= 0 && i+j < n && s[i-j+1] == s[i+j]; ++j) cut[i+j+1] = min(cut[i+j+1], cut[i-j+1]+1); } |
The complete code is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | int minCut(string s) { int n = s.size(); if (n <= 1) return 0; vector< int > cut(n+1, 0); for ( int i = 0; i <= n; i++) cut[i] = i-1; for ( int i = 0; i < n; ++i) { //odd length, i.e. i is the middle point, [i-j, ..., i, ..., i+j]; for ( int j = 0; i-j >= 0 && i+j < n && s[i-j] == s[i+j]; ++j) cut[i+j+1] = min(cut[i+j+1], cut[i-j]+1); //even length, i.e. i is left side's endpoint, [i-(j-1), ..., i, i+1, ..., i+j]; for ( int j = 1; i-j+1 >= 0 && i+j < n && s[i-j+1] == s[i+j]; ++j) cut[i+j+1] = min(cut[i+j+1], cut[i-j+1]+1); } return cut[n]; } |
The running time is about two parts. The first is the assignment of , .
The second part is divided by two for loop:
So the total running time is .
And obviously the space is .
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)