Given a non-empty string, encode the string such that its encoded length is the shortest.
The encoding rule is: k[encoded_string]
, where the encoded_string inside the square brackets is being repeated exactly k times.
Note:
- k will be a positive integer and encoded string will not be empty or have extra space.
- You may assume that the input string contains only lowercase English letters. The string's length is at most 160.
- If an encoding process does not make the string shorter, then do not encode it. If there are several solutions, return any of them is fine.
Example 1:
Input: "aaa" Output: "aaa" Explanation: There is no way to encode it such that it is shorter than the input string, so we do not encode it.
Example 2:
Input: "aaaaa" Output: "5[a]" Explanation: "5[a]" is shorter than "aaaaa" by 1 character.
Example 3:
Input: "aaaaaaaaaa" Output: "10[a]" Explanation: "a9[a]" or "9[a]a" are also valid solutions, both of them have the same length = 5, which is the same as "10[a]".
Example 4:
Input: "aabcaabcd" Output: "2[aabc]d" Explanation: "aabc" occurs twice, so one answer can be "2[aabc]d".
Example 5:
Input: "abbbabbbcabbbabbbc" Output: "2[2[abbb]c]" Explanation: "abbbabbbc" occurs twice, but "abbbabbbc" can also be encoded to "2[abbb]c", so one answer can be "2[2[abbb]c]".
思路:这题因为中间任意重复字符都可以形成重复,所以这是一个长度区间型动态规划,从len最小的开始计算,一直计算到最大的。dp[i][j]代表从i,....j 最小的compress string,dp[i][j] , 可以从两个方面得到, dp[i][k] + dp[k + 1][j] 如果合起来比当前小,update
如果dp[i][j] 自己能够组成最小的compression,也需要update。注意判断最小的compress string的时候,用pattern去判断,
pattern != null && substr.length() % pattern.length() == 0 && substr.replaceAll(pattern, "").length() == 0) 这句代码很巧妙,学习了。另外,长度dp的模板要记住:
for(int len = 1; len <= n; len++) {
for(int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
class Solution {
public String encode(String s) {
int n = s.length();
String[][] dp = new String[n][n];
for(int len = 1; len <= n; len++) {
for(int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
String substr = s.substring(i, j + 1);
dp[i][j] = substr;
// 看左右两边能否组合成最小的string;
if(j - i >= 4) {
for(int k = i; k < j; k++) {
if(dp[i][k].length() + dp[k + 1][j].length() < dp[i][j].length()) {
dp[i][j] = dp[i][k] + dp[k + 1][j];
}
}
}
// 看自己能否组成最小的string;
for(int k = 0; k < substr.length(); k++) {
// 遍历所有的可能pattern;
String pattern = substr.substring(0, k + 1);
if(pattern != null
&& (substr.length() % pattern.length() == 0)
&& substr.replaceAll(pattern, "").length() == 0) {
String candidate = substr.length() / pattern.length()
+ "[" + dp[i][i + k] + "]";
if(candidate.length() < dp[i][j].length()) {
dp[i][j] = candidate;
}
}
}
}
}
return dp[0][n - 1];
}
}