664. Strange Printer (區間型 dp
Can see the screenshot explanation as well.
class Solution {
public int strangePrinter(String s) {
Integer[][] memo = new Integer[s.length()][s.length()];
return dfs(s, 0, s.length()-1, memo);
}
private int dfs(String s, int i, int j, Integer[][] memo) {
if (i == j) {
return 1;
}
if (memo[i][j] != null) {
return memo[i][j];
}
int minTurns = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
minTurns = Math.min(
minTurns,
dfs(s, i, k, memo) + dfs(s, k+1, j, memo)
);
}
memo[i][j] = (s.charAt(i) == s.charAt(j) ? minTurns - 1 : minTurns);
return memo[i][j];
}
}
/**
This will seperate to all substring -> O(n^2)
Time Complexity Analysis
Subproblem Count:
The function helper(s, i, j, memo) is called for every possible substring s[i...j].
Since i can range from 0 to n-1 and j can range from i to n-1,
the total number of unique subproblems is approximately the number of pairs (i, j) where i ≤ j.
There are
n^2
such pairs, so the total number of subproblems is
O(n^2).
Cost per Subproblem:
For each subproblem, the function attempts to split the string at every possible point k
between i and j-1.
This involves checking up to j−i possible splits.
In the worst case,
j−i can be as large as n−1.
Therefore, the time spent on each subproblem is
O(n)
Total Time Complexity:
Since there are
O(n^2) subproblems, and each subproblem can take up to O(n) time to solve,
the total time complexity is O(n^3)
thought
we want to find a break point to seperate to "2" part sub problem
keep do the dfs to sepeate to 2 part, until i == j (one char) so there is 1 turn
ex: dfs(a) = 1 this is the base case
like
"aaabbb" -> to
a aabbb
or
aa abbb
or
aaa bbb
or
aaab bb
or
aaabb b
see which one has the min turns
so we can record memo[i][j] which means from i to j the min turns in this substring
but notice, because when same char, we can print a seq, so like aaa -> only needs one turns, not 3 turns
so in every dfs(), we have to check if char[i] == char[j] -> then turns - 1
so dfs(aaa) = dfs(a) + dfs(aa) or dfs(aa) + dfs(a)
so dfs(aa) = dfs(a) + dfs(a) = 2 but char[i] == char[j], so dfs(aa) = 1
then dfs(aaa) = dfs(a) + dfs(aa) = 1+1 = 2, char[i] == char[j], so dfs(aaa) = 1
like a dfs 推論出來的結果! this part is really hard!
ex1:
i.j
abc
because if runs a for in k
min(
dfs(a) + dfs(bc) = 1 + 2
,
dfs(ab) + dfs(c) = 2 +1
)
dfs(bc) -> dfs(b) + dfs(c)
dfs(a) dfs(b) = 1+1 = 2
ex2:
aba
2 + 1 -> but (s.charAt(i) == s.charAt(j)) -> so 3 -1 = 2
ex3:
aaabbb
= min(
dfs(a) + dfs(aabbb)
or
dfs(aa) + dfs(abbb)
or
dfs(aaa) + dfs(bbb) =
min(
dfs(a) + dfs(aa) + dfs(b) + dfs(bb) -> (so dfs(aa = 1), because but i == j)
dfs(aaa) = 2 -> but i == j so 2 -1 again
vice versa, dfs(bbb) = 1. so best ans is dfs(aaa) + dfs(bbb) = 1 + 1 = 2
or
dfs(aa) + dfs(a) + dfs(bb) + dfs(b)
)
or
dfs(aaab) + dfs(bb)
or
dfs(aaabb) + dfs(b)
)
dfs(aabbb) =
min...
so actually we can find in i to j, the best solution, so it's a interval dp
we can use memo[i][j] to record the min turns in i to j
*/refer to:
https://leetcode.com/problems/strange-printer/discuss/152758/Clear-Logical-Thinking-with-Code
refer to:

DFS + memo
T: O(n* (n/2)+(n/2) * (...) => ?

so
dp
T: O(n^3)
S: O(n^2)
Last updated
Was this helpful?