You are given a string s consisting of only lowercase English letters. In one operation, you can:
Delete the entire strings, or
Delete the firsti letters of s if the first i letters of s are equal to the following i letters in s, for any i in the range 1 <= i <= s.length / 2.
For example, if s = "ababc", then in one operation, you could delete the first two letters of s to get "abc", since the first two letters of s
and the following two letters of s are both equal to "ab".
Return _themaximum number of operations needed to delete all of _s.
Input: s ="abcabcdabc"Output: 2Explanation:
- Delete the first 3letters("abc") since the next 3 letters are equal. Now, s ="abcdabc".- Delete all the letters.We used 2 operations so return2. It can be proven that 2is the maximum number of operations needed.Note that in the second operation we cannot delete"abc" again because the next occurrence of "abc" does not happen in the next 3 letters.
Input: s ="aaabaab"Output: 4Explanation:
- Delete the first letter("a") since the next letter is equal. Now, s ="aabaab".- Delete the first 3letters("aab") since the next 3 letters are equal. Now, s ="aab".- Delete the first letter("a") since the next letter is equal. Now, s ="ab".- Delete all the letters.We used 4 operations so return4. It can be proven that 4is the maximum number of operations needed.
The key idea is to use dynamic programming to find the maximum number of deletions. For each substring, we check if the first i characters are equal to the next i characters, which allows us to delete the prefix. Rolling hash helps us compare substrings efficiently, and we use a table to store the longest common prefix (lcp[i][j]) between substrings starting at i and j.
classSolution {
publicintdeleteString(String s) {
int n = s.length();
int[][] lcp =newint[n+1][n+1];
for (int i = n-1; i >= 0; i--) {
for (int j = n-1; j >= 0; j--) {
if (s.charAt(i) == s.charAt(j)) {
lcp[i][j]= lcp[i+1][j+1]+ 1;
}
}
}
int[] dp =newint[n+1];
for (int i = n-1; i >= 0; i--) {
dp[i]= 1;
for (int j = 1; i+2*j <= n; j++) {
if (lcp[i][i+j]>= j) {
dp[i]= Math.max(dp[i], 1 + dp[i+j]);
}
}
}
return dp[0];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
fundeleteString(s: String): Int {
val n = s.length
val lcp = Array(n+1) { IntArray(n+1) }
for (i in n-1 downTo 0) {
for (j in n-1 downTo 0) {
if (s[i] == s[j]) lcp[i][j] = lcp[i+1][j+1] + 1 }
}
val dp = IntArray(n+1)
for (i in n-1 downTo 0) {
dp[i] = 1for (j in1..((n-i)/2)) {
if (lcp[i][i+j] >= j) dp[i] = maxOf(dp[i], 1 + dp[i+j])
}
}
return dp[0]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
defdeleteString(s: str) -> int:
n = len(s)
lcp = [[0]*(n+1) for _ in range(n+1)]
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
if s[i] == s[j]:
lcp[i][j] = lcp[i+1][j+1] +1 dp = [0]*(n+1)
for i in range(n-1, -1, -1):
dp[i] =1for j in range(1, (n-i)//2+1):
if lcp[i][i+j] >= j:
dp[i] = max(dp[i], 1+ dp[i+j])
return dp[0]
impl Solution {
pubfndelete_string(s: String) -> i32 {
let n = s.len();
let s = s.as_bytes();
letmut lcp =vec![vec![0; n+1]; n+1];
for i in (0..n).rev() {
for j in (0..n).rev() {
if s[i] == s[j] {
lcp[i][j] = lcp[i+1][j+1] +1;
}
}
}
letmut dp =vec![0; n+1];
for i in (0..n).rev() {
dp[i] =1;
for j in1..=((n-i)/2) {
if lcp[i][i+j] >= j {
dp[i] = dp[i].max(1+ dp[i+j]);
}
}
}
dp[0]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
deleteString(s: string):number {
constn=s.length;
constlcp: number[][] = Array.from({length: n+1}, () => Array(n+1).fill(0));
for (leti=n-1; i>=0; i--) {
for (letj=n-1; j>=0; j--) {
if (s[i] ===s[j]) lcp[i][j] =lcp[i+1][j+1] +1;
}
}
constdp: number[] = Array(n+1).fill(0);
for (leti=n-1; i>=0; i--) {
dp[i] =1;
for (letj=1; i+2*j<=n; j++) {
if (lcp[i][i+j] >=j) dp[i] = Math.max(dp[i], 1+dp[i+j]);
}
}
returndp[0];
}
}