我需要根据一组范围值将一个字符串分成多个子字符串,每个子字符串都标记有一组适用范围。结果的子字符串集合中不应有重叠,并且与集合中任何范围都不匹配的子字符串仍需要包含在结果中。
当前,我遍历字符串以找到每个字符的匹配范围,然后循环遍历该迭代的结果以基于连续的匹配范围集构建每个子字符串。但是,我敢肯定,这样做的效率更高。
此应用程序是用C#编写的,但是也可以接受用于解决此问题的算法的文字描述。
让字符串为:
selerisquesuspensione congue居民scelerisque sociis placerat a himenaeos diam nunc前庭未成年人nisl himenaeos viverra mus hac。
让范围指定为开始和结束索引(包括开始和结束):
结果应为:
范围永远不会为零长度。分割操作的结果也不应包含任何零长度的子字符串。
除了简单的重叠之外,多个范围可以具有相同的起始索引或结束索引。上面的示例中没有对此进行演示。
答案 0 :(得分:1)
此功能假定事件具有唯一索引。需要进行一些修改以处理[[12,50),(12,40),(15、50)]之类的事情。
答案 1 :(得分:0)
这是我最基本的最坏情况的实现,先用O(m * n)构建rangedChars
,然后用O(n log n)将其转换为substrings
。
我自己编写的代码不是使用包含范围的范围,而是在开始和长度上起作用。
var text = "Scelerisque suspendisse congue habitant scelerisque sociis placerat a himenaeos diam nunc vestibulum nec ultrices nisl himenaeos viverra mus hac.";
var ranges = new Range[]
{
new Range(12, 39),
new Range(24, 6),
new Range(59, 30),
new Range(80, 24),
new Range(114, 14)
};
var rangedChars = new RangedChar[text.Length];
for (int i = 0; i < text.Length; i++)
rangedChars[i] = new RangedChar(i, text[i], ranges.Where(r => r.ContainsIndex(i)));
var substrings = new List<RangedString>();
for (int i = 0; i < rangedChars.Length; )
{
var appliedRanges = rangedChars[i].Ranges;
int j = i + 1;
while (j < rangedChars.Length && appliedRanges.SequenceEqual(rangedChars[j].Ranges))
j++;
var substring = String.Join("", text.Substring(i, j - i));
substrings.Add(new RangedString(i, substring, appliedRanges));
i = j;
}
return substrings;
// supporting types
readonly struct Range
{
public int Start { get; }
public int Length { get; }
public Range(int start, int end) { Start = start; End = end; }
public bool ContainsIndex(int index) => index >= Start && index < (Start + Length);
}
public class RangedChar
{
public int Index { get; }
public char Character { get; }
public IReadOnlyList<Range> Ranges { get; }
public RangedChar(int index, char character, IEnumerable<Range> ranges)
{
Index = index;
Character = character;
Ranges = ranges.ToList();
}
}
public class RangedString
{
public int Start { get; }
public string Text { get; }
public IReadOnlyList<Range> Ranges { get; }
public RangedString(int start, string text, IEnumerable<Range> ranges)
{
Start = start;
Text = text;
Ranges = ranges.ToList();
}
}