Instead of the old Tuple objects, you should use ValueTuple. They are more flexible and easier to read and maintain according to names and is further more elaborated and incorporated in C# as language. So your Dictionary could look like:
var index2strings = new SortedDictionary<int, (string source, string target)>();
for (int i = 0; i < indexes.Length; i++)
{
index2strings.Add(indexes[i], (sources[i], targets[i]));
}
You can benefit from setting the capacity of the string builder to a large value, - maybe as:
StringBuilder res = new StringBuilder(S.Length * 2);
Because SortedDictionary<K,V> provides a "decontructor", you can replace this:
foreach (var item in index2strings)
{
var index = item.Key;
var source = item.Value.Item1;
var target = item.Value.Item2;
with this:
foreach ((var index, (var source, var target)) in index2strings)
{
if you use ValueTuple as suggested above.
This:
for (int k = curr; k < index; k++)
{
res.Append(S[k]);
curr++;
}
can be replaced with:
int length = index - curr;
res.Append(S.Substring(curr, length));
curr += length;
According to my measurements its cheaper to add one string as a whole than a sequence of its chars.
Likewise can this:
//check the entire prefix is found
bool isFound = true;
for (int sIndx = index, j = 0; sIndx < index + source.Length; sIndx++, j++)
{
if (S[sIndx] != source[j])
{
isFound = false;
break;
}
}
if (!isFound)
{
continue;
}
be replaced with:
if (S.Substring(index, source.Length) != source)
{
continue;
}
and this:
foreach (var t in target)
{
res.Append(t);
}
with:
res.Append(target);
and finally this:
for (int i = curr; i < S.Length; i++)
{
res.Append(S[i]);
}
with:
res.Append(S.Substring(curr));
When doing so it seems that you can cut the duration to about a little lesser than half the time.