Backtracking
Dynamic Programming
String
Description
Given a string s
, partition s
such that every substring of the partition is a palindrome . Return all possible palindrome partitioning of s
.
Example 1:
Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]
Example 2:
Input: s = "a"
Output: [["a"]]
Constraints:
1 <= s.length <= 16
s
contains only lowercase English letters.
Solutions
Solution 1: Preprocessing + DFS (Backtracking)
We can use dynamic programming to preprocess whether any substring in the string is a palindrome, i.e., \(f[i][j]\) indicates whether the substring \(s[i..j]\) is a palindrome.
Next, we design a function \(dfs(i)\) , which represents starting from the \(i\) -th character of the string and partitioning it into several palindromic substrings, with the current partition scheme being \(t\) .
If \(i = |s|\) , it means the partitioning is complete, and we add \(t\) to the answer array and then return.
Otherwise, we can start from \(i\) and enumerate the end position \(j\) from small to large. If \(s[i..j]\) is a palindrome, we add \(s[i..j]\) to \(t\) , then continue to recursively call \(dfs(j+1)\) . When backtracking, we need to pop \(s[i..j]\) .
The time complexity is \(O(n \times 2^n)\) , and the space complexity is \(O(n^2)\) . Here, \(n\) is the length of the string.
Python3 Java C++ Go TypeScript C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 class Solution :
def partition ( self , s : str ) -> List [ List [ str ]]:
def dfs ( i : int ):
if i == n :
ans . append ( t [:])
return
for j in range ( i , n ):
if f [ i ][ j ]:
t . append ( s [ i : j + 1 ])
dfs ( j + 1 )
t . pop ()
n = len ( s )
f = [[ True ] * n for _ in range ( n )]
for i in range ( n - 1 , - 1 , - 1 ):
for j in range ( i + 1 , n ):
f [ i ][ j ] = s [ i ] == s [ j ] and f [ i + 1 ][ j - 1 ]
ans = []
t = []
dfs ( 0 )
return ans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 class Solution {
private int n ;
private String s ;
private boolean [][] f ;
private List < String > t = new ArrayList <> ();
private List < List < String >> ans = new ArrayList <> ();
public List < List < String >> partition ( String s ) {
n = s . length ();
f = new boolean [ n ][ n ] ;
for ( int i = 0 ; i < n ; ++ i ) {
Arrays . fill ( f [ i ] , true );
}
for ( int i = n - 1 ; i >= 0 ; -- i ) {
for ( int j = i + 1 ; j < n ; ++ j ) {
f [ i ][ j ] = s . charAt ( i ) == s . charAt ( j ) && f [ i + 1 ][ j - 1 ] ;
}
}
this . s = s ;
dfs ( 0 );
return ans ;
}
private void dfs ( int i ) {
if ( i == s . length ()) {
ans . add ( new ArrayList <> ( t ));
return ;
}
for ( int j = i ; j < n ; ++ j ) {
if ( f [ i ][ j ] ) {
t . add ( s . substring ( i , j + 1 ));
dfs ( j + 1 );
t . remove ( t . size () - 1 );
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 class Solution {
public :
vector < vector < string >> partition ( string s ) {
int n = s . size ();
bool f [ n ][ n ];
memset ( f , true , sizeof ( f ));
for ( int i = n - 1 ; i >= 0 ; -- i ) {
for ( int j = i + 1 ; j < n ; ++ j ) {
f [ i ][ j ] = s [ i ] == s [ j ] && f [ i + 1 ][ j - 1 ];
}
}
vector < vector < string >> ans ;
vector < string > t ;
auto dfs = [ & ]( this auto && dfs , int i ) -> void {
if ( i == n ) {
ans . emplace_back ( t );
return ;
}
for ( int j = i ; j < n ; ++ j ) {
if ( f [ i ][ j ]) {
t . emplace_back ( s . substr ( i , j - i + 1 ));
dfs ( j + 1 );
t . pop_back ();
}
}
};
dfs ( 0 );
return ans ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 func partition ( s string ) ( ans [][] string ) {
n := len ( s )
f := make ([][] bool , n )
for i := range f {
f [ i ] = make ([] bool , n )
for j := range f [ i ] {
f [ i ][ j ] = true
}
}
for i := n - 1 ; i >= 0 ; i -- {
for j := i + 1 ; j < n ; j ++ {
f [ i ][ j ] = s [ i ] == s [ j ] && f [ i + 1 ][ j - 1 ]
}
}
t := [] string {}
var dfs func ( int )
dfs = func ( i int ) {
if i == n {
ans = append ( ans , append ([] string ( nil ), t ... ))
return
}
for j := i ; j < n ; j ++ {
if f [ i ][ j ] {
t = append ( t , s [ i : j + 1 ])
dfs ( j + 1 )
t = t [: len ( t ) - 1 ]
}
}
}
dfs ( 0 )
return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 function partition ( s : string ) : string [][] {
const n = s . length ;
const f : boolean [][] = Array . from ({ length : n }, () => Array ( n ). fill ( true ));
for ( let i = n - 1 ; i >= 0 ; -- i ) {
for ( let j = i + 1 ; j < n ; ++ j ) {
f [ i ][ j ] = s [ i ] === s [ j ] && f [ i + 1 ][ j - 1 ];
}
}
const ans : string [][] = [];
const t : string [] = [];
const dfs = ( i : number ) => {
if ( i === n ) {
ans . push ( t . slice ());
return ;
}
for ( let j = i ; j < n ; ++ j ) {
if ( f [ i ][ j ]) {
t . push ( s . slice ( i , j + 1 ));
dfs ( j + 1 );
t . pop ();
}
}
};
dfs ( 0 );
return ans ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class Solution {
private int n ;
private string s ;
private bool [,] f ;
private IList < IList < string >> ans = new List < IList < string >> ();
private IList < string > t = new List < string > ();
public IList < IList < string >> Partition ( string s ) {
n = s . Length ;
this . s = s ;
f = new bool [ n , n ];
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = 0 ; j <= i ; ++ j ) {
f [ i , j ] = true ;
}
}
for ( int i = n - 1 ; i >= 0 ; -- i ) {
for ( int j = i + 1 ; j < n ; ++ j ) {
f [ i , j ] = s [ i ] == s [ j ] && f [ i + 1 , j - 1 ];
}
}
dfs ( 0 );
return ans ;
}
private void dfs ( int i ) {
if ( i == n ) {
ans . Add ( new List < string > ( t ));
return ;
}
for ( int j = i ; j < n ; ++ j ) {
if ( f [ i , j ]) {
t . Add ( s . Substring ( i , j + 1 - i ));
dfs ( j + 1 );
t . RemoveAt ( t . Count - 1 );
}
}
}
}
GitHub