我正在编写一个程序,我想将相邻的子串分组,例如ABCABCBC可以压缩为2ABC1BC或1ABCA2BC。
在所有可能的选项中,我想找到最小长度的结果字符串。
这是我到目前为止写的代码,但没有做好工作。在这方面请帮助我。
#include <algorithm>
bool findAllDigits(istream & i){
vector<char> digits(0); char c;
while(i >> c)//read one char
if(isdigit(c) && find(digits.begin(), digits.end(), c)==digits.end())//check if it is a number and not in the vector
digits.push_back(c);
return digits.size() == 10;//return true if all the digits are in the stream
}
答案 0 :(得分:2)
您可以使用递归执行此操作。我不能给你一个C#解决方案,因为我这里没有C#编译器,但是一般的想法和python解决方案也可以解决这个问题。
所以你有一个输入字符串ABCABCBC
。并且您希望将其转换为run length encoding的高级变体(我们称之为高级RLE )。
我的想法包含一个通用的第一个想法,然后我应用递归:
shortest_repr(string)
。您可以将字符串分为前缀和后缀,然后检查前缀是否可以在后缀的开头找到。对于您的输入示例,这将是:
此输入可以放入函数shorten_prefix
,该函数检查后缀以前缀开头的频率(例如前缀ABC
和后缀ABCBC
,前缀在后缀的开头只有一次,总共有2 ABC
跟随。因此,我们可以将此前缀/后缀组合压缩为输出(2ABC, BC)
。
此函数shorten_prefix
将在循环中的每个元组上使用。
使用函数shorten_prefix
一次后,大多数字符串组合仍然有后缀。例如。在输出(2ABC, BC)
中,仍然有字符串BC
作为后缀。因此,需要找到剩余后缀的最短表示。哇,我们仍然有一个名为shortest_repr
的函数,所以让我们把它称为剩下的后缀。
此图像显示此递归的工作原理(我只扩展了第3级之后的一个节点,但实际上所有的橙色圆圈都会经过递归):
我们从shortest_repr
调用字符串ABABB
开始在顶部(我选择了较短的图像样本)。然后,我们在所有可能的拆分位置拆分此字符串,并在第二行中获取前缀/后缀对的列表。在此列表的每个元素上,我们首先调用前缀/后缀优化(shorten_prefix
)并检索缩短的前缀/后缀组合,该组合已在前缀(第三行)中具有游程长度数字。现在,在每个后缀上,我们调用递归函数shortest_repr
。
我没有显示递归的向上方向。当后缀为空字符串时,我们将空字符串传递给shortest_repr
。当然,空字符串的最短表示形式是空字符串,因此我们可以立即返回空字符串。
当在我们的循环中收到对shortest_repr
的调用结果时,我们只选择循环内的最短字符串并返回它。
这是一些快速入侵的代码,可以解决这个问题:
def shorten_beginning(beginning, ending):
count = 1
while ending.startswith(beginning):
count += 1
ending = ending[len(beginning):]
return str(count) + beginning, ending
def find_shortest_repr(string):
possible_variants = []
if not string:
return ''
for i in range(1, len(string) + 1):
beginning = string[:i]
ending = string[i:]
shortened, new_ending = shorten_beginning(beginning, ending)
shortest_ending = find_shortest_repr(new_ending)
possible_variants.append(shortened + shortest_ending)
return min([(len(x), x) for x in possible_variants])[1]
print(find_shortest_repr('ABCABCBC'))
print(find_shortest_repr('ABCABCABCABCBC'))
print(find_shortest_repr('ABCABCBCBCBCBCBC'))
我认为这种方法与recursive levenshtein distance calculation存在同样的问题。它多次计算相同的时间。因此,尝试使用动态编程实现此功能将是一个很好的练习。
答案 1 :(得分:0)
如果这不是代码中的学校作业或性能关键部分,RegEx
可能就足够了:
string input = "ABCABCBC";
var re = new Regex(@"(.+)\1+|(.+)", RegexOptions.Compiled); // RegexOptions.Compiled is optional if you use it more than once
string output = re.Replace(input,
m => (m.Length / m.Result("$1$2").Length) + m.Result("$1$2")); // "2ABC1BC" (case sensitive by default)