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:

  1. k will be a positive integer and encoded string will not be empty or have extra space.
  2. You may assume that the input string contains only lowercase English letters. The string's length is at most 160.
  3. 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]".
 
这道题让我们压缩字符串,把相同的字符串用中括号括起来,然后在前面加上出现的次数,感觉还是一道相当有难度的题呢。参考了网上大神的帖子才弄懂该怎么做,这道题还是应该用DP来做。我们建立一个二维的DP数组,其中dp[i][j]表示s在[i, j]范围内的字符串的缩写形式(如果缩写形式长度大于子字符串,那么还是保留子字符串),那么如果s字符串的长度是n,最终我们需要的结果就保存在dp[0][n-1]中,然后我们需要遍历s的所有子字符串,对于任意一段子字符串[i, j],我们\\我们以中间任意位置k来拆分成两段,比较dp[i][k]加上dp[k+1][j]的总长度和dp[i][j]的长度,将长度较小的字符串赋给dp[i][j],然后我们要做的就是在s中取出[i, j]范围内的子字符串t进行合并。合并的方法是我们在取出的字符串t后面再加上一个t,然后在这里面寻找子字符串t的第二个起始位置,如果第二个起始位置小于t的长度的话,说明t包含重复字符串,举个例子吧,比如 t = "abab", 那么t+t = "abababab",我们在里面找第二个t出现的位置为2,小于t的长度4,说明t中有重复出现,重复的个数为t.size()/pos = 2个,那么我们就要把重复的地方放入中括号中,注意中括号里不能直接放这个子字符串,而是应该从dp中取出对应位置的字符串,因为重复的部分有可能已经写成缩写形式了,比如题目中的例子5。再看一个例子,如果t = "abc",那么t+t = "abcabc",我们在里面找第二个t出现的位置为3,等于t的长度3,说明t中没有重复出现,那么replace就还是t。然后我们比较我们得到的replace和dp[i][j]中的字符串长度,把长度较小的赋给dp[i][j]即可,时间复杂度为O(n3),空间复杂度为O(n2),参见代码如下:
 
解法一:
class Solution {
public:
string encode(string s) {
int n = s.size();
vector<vector<string>> dp(n, vector<string>(n, ""));
for (int step = ; step <= n; ++step) {
for (int i = ; i + step - < n; ++i) {
int j = i + step - ;
dp[i][j] = s.substr(i, step);
for (int k = i; k < j; ++k) {
string left = dp[i][k], right = dp[k + ][j];
if (left.size() + right.size() < dp[i][j].size()) {
dp[i][j] = left + right;
}
}
string t = s.substr(i, j - i + ), replace = "";
auto pos = (t + t).find(t, );
if (pos >= t.size()) replace = t;
else replace = to_string(t.size() / pos) + '[' + dp[i][i + pos - ] + ']';
if (replace.size() < dp[i][j].size()) dp[i][j] = replace;
}
}
return dp[][n - ];
}
};

根据热心网友iffalse的留言,我们可以优化上面的方法。如果t是重复的,是不是就不需要再看left.size() + right.size() < dp[i][j].size()了。例如t是abcabcabcabcabc, 最终肯定是5[abc],不需要再看3[abc]+abcabc或者abcabc+3[abc]。对于一个本身就重复的字符串,最小的长度肯定是n[REPEATED],不会是某个left+right。所以应该把k的那个循环放在t和replace那部分代码的后面。这样的确提高了一些运算效率的,参见代码如下:

解法二:

class Solution {
public:
string encode(string s) {
int n = s.size();
vector<vector<string>> dp(n, vector<string>(n, ""));
for (int step = ; step <= n; ++step) {
for (int i = ; i + step - < n; ++i) {
int j = i + step - ;
dp[i][j] = s.substr(i, step);
string t = s.substr(i, j - i + ), replace = "";
auto pos = (t + t).find(t, );
if (pos < t.size()) {
replace = to_string(t.size() / pos) + "[" + dp[i][i + pos - ] + "]";
if (replace.size() < dp[i][j].size()) dp[i][j] = replace;
continue;
}
for (int k = i; k < j; ++k) {
string left = dp[i][k], right = dp[k + ][j];
if (left.size() + right.size() < dp[i][j].size()) {
dp[i][j] = left + right;
}
}
}
}
return dp[][n - ];
}
};

类似题目:

Decode String

Number of Atoms

参考资料:

https://leetcode.com/problems/encode-string-with-shortest-length/

https://leetcode.com/problems/encode-string-with-shortest-length/discuss/95599/Accepted-Solution-in-Java

https://leetcode.com/problems/encode-string-with-shortest-length/discuss/95605/Easy-to-understand-C%2B%2B-O(n3)-solution

https://leetcode.com/problems/encode-string-with-shortest-length/discuss/95619/C%2B%2B-O(N3)-time-O(N2)-space-solution-using-memorized-dynamic-programming-with-detail-explanations

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Encode String with Shortest Length 最短长度编码字符串的更多相关文章

  1. Leetcode: Encode String with Shortest Length && G面经

    Given a non-empty string, encode the string such that its encoded length is the shortest. The encodi ...

  2. Leetcode 8. String to Integer (atoi) atoi函数实现 (字符串)

    Leetcode 8. String to Integer (atoi) atoi函数实现 (字符串) 题目描述 实现atoi函数,将一个字符串转化为数字 测试样例 Input: "42&q ...

  3. 【LeetCode每天一题】Length of Last Word(字符串中最后一个单词的长度)

    Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the l ...

  4. [LeetCode] Construct String from Binary Tree 根据二叉树创建字符串

    You need to construct a string consists of parenthesis and integers from a binary tree with the preo ...

  5. [LeetCode] Decode String 解码字符串

    Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...

  6. LeetCode : Given a string, find the length of the longest serial substring without repeating characters.

    Given a string, find the length of the longest serial substring without repeating characters. Exampl ...

  7. Leetcode 943. Find the Shortest Superstring(DP)

    题目来源:https://leetcode.com/problems/find-the-shortest-superstring/description/ 标记难度:Hard 提交次数:3/4 代码效 ...

  8. hust--------The Minimum Length (最短循环节)(kmp)

    F - The Minimum Length Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%lld & %l ...

  9. [LeetCode] Reverse String II 翻转字符串之二

    Given a string and an integer k, you need to reverse the first k characters for every 2k characters ...

随机推荐

  1. springboot(八):RabbitMQ详解

    RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将RocketMQ捐献给了apa ...

  2. 1.C#面向对象基础简介

    学习核心内容: 面向对象的三个特性:封装.继承.多态 访问级别:用处在于控制成员在那些地方可以访问,这样达到面向对象封装的目的. 常用级别:public (任何地方都可以访问) private(默认级 ...

  3. PHP函数基础知识.png

  4. windows go安装

    1.安装git 因为golang是通过git来管理远程包的,所以我们首先要安装git,下载地址:http://www.git-scm.com/download/. git安装比较简单,直接下一步即可( ...

  5. [Android]Dagger2Metrics - 测量DI图表初始化的性能(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5098943.html Dagger2Metrics - 测量D ...

  6. Google C++单元测试框架GoogleTest(总)

    之前一个月都在学习googletest框架,对googletest的文档都翻译了一遍,也都发在了之前的博客里,另外其实还有一部分的文档我没有发,就是GMock的CookBook部分:https://g ...

  7. Android中使用ImageViewSwitcher实现图片切换轮播导航效果

    前面写过了使用ViewFlipper和ViewPager实现屏幕中视图切换的效果(ViewPager未实现轮播)附链接: Android中使用ViewFlipper实现屏幕切换 Android中使用V ...

  8. EXD_BAD_ACCEEE

    iOS开发过程中,普通的bug通常较容易定位问题所在,但是,EXD_BAD_ACCEEE问题却比较不易查找问题.本文记录下解决EXD_BAD_ACCEEE问题的过程.首先说一下 EXC_BAD_ACC ...

  9. IOS的七种手势

    今天为大家介绍一下IOS 的七种手势,手势在开发中经常用到,所以就简单 通俗易懂的说下, 话不多说,直接看代码: // 初始化一个UIimageView UIImageView *imageView ...

  10. iOS版打地鼠游戏源码

    打地鼠游戏源码,游戏是一款多关卡基于cocos2d的iPad打地鼠游戏源码,这也是一款高质量的打地鼠游戏源码,可以拥有逐步上升的关卡的设置,大家可以在关卡时设置一些商业化的模式来盈利的,非常完美的一款 ...