我正在研究压缩算法,我想用它的数学形式替换所有连续数。它在数学上不是逻辑的,但我的算法会知道并将其转换为原始形式。
假设我有字符串:
string input = "732183900000000000002389288888888888888";
您是否看到它有0000000000和8888888888是主要的连续重复
现在我想把它们转换成:
//convert 000000000 to 0*9. Means 9 times 0.
//convert 888888888 to 8*9. Means 8 times 0.
string output = "7321839" +
"0*13" +
"23892" +
"8*14";
//or
string output = "7321839-0*13-23892-8*14";
需要考虑的要点:
在窗口上运行的任何语言都将被接受。对我来说,最重要的是算法
请记住性能,因为它将用于大文件。
老实说,这很简单:
- 一次分析一个字符串
- 检查上一个字符是否与当前字符相同
- 如果相同,则递增计数器变量或将其重置为0
- 当我们将计数器重置为0时,如果计数器值大于1,则在结果中添加*
Regex可能对此有点复杂,因为有破折号规则(尽管并非不可能(,
看起来,你想要以下
- 相同数量的组大于1的计数
- 无前缀破折号
- 无后缀破折号
- 没有双破折号(推测性(
这里有一个相当有效的带有StringBuilder
的C#O(n(实现,它应该允许您使用最小分配处理超大字符串
给定
public static string Shorten(string value)
{
var sb = new StringBuilder(value.Length);
int i, last;
var isLastGroup = false;
void Write()
{
var isGroup = i - last > 1;
var getDash = last == 0 || isLastGroup ? "" : "-";
sb.Append(isGroup ? $"{getDash}{value[last]}*{i - last}{(i != value.Length ? "-" : "")}" : value[last].ToString());
isLastGroup = isGroup;
last = i;
}
for (i = 0, last = 0; i < value.Length; i++)
if (value[last] != value[i])
Write();
Write();
return sb.ToString();
}
测试
Console.WriteLine(Shorten("1"));
Console.WriteLine(Shorten("111"));
Console.WriteLine(Shorten("1112"));
Console.WriteLine(Shorten("1222"));
Console.WriteLine(Shorten("12233344445555512345"));
结果
1
13
13-23
1-22-33-44-5*5-12345
此处的完整演示