实现一个算法,该算法将两个字符串作为输入,并返回两者的交集,每个字母最多代表一次。
Algo :(考虑使用的语言是c#)
这是一个O(n)解决方案但是使用了额外的空间,2个char数组和一个哈希表
你能想到比这更好的解决方案吗?
答案 0 :(得分:10)
这个怎么样......
var s1 = "aabbccccddd";
var s2 = "aabc";
var ans = s1.Intersect(s2);
答案 1 :(得分:2)
没有测试过这个,但这是我的想法:
不会使用额外的内存,只需要两个原始字符串,两个整数和一个输出字符串(或StringBuilder)。作为额外的奖励,输出值也将被排序!
第2部分: 这就是我要写的内容(对于注释感到抱歉,对于stackoverflow是新的):
private static string intersect(string left, string right)
{
StringBuilder theResult = new StringBuilder();
string sortedLeft = Program.sort(left);
string sortedRight = Program.sort(right);
int leftIndex = 0;
int rightIndex = 0;
// Work though the string with the "first last character".
if (sortedLeft[sortedLeft.Length - 1] > sortedRight[sortedRight.Length - 1])
{
string temp = sortedLeft;
sortedLeft = sortedRight;
sortedRight = temp;
}
char lastChar = default(char);
while (leftIndex < sortedLeft.Length)
{
char nextChar = (sortedLeft[leftIndex] <= sortedRight[rightIndex]) ? sortedLeft[leftIndex++] : sortedRight[rightIndex++];
if (lastChar == nextChar) continue;
theResult.Append(nextChar);
lastChar = nextChar;
}
// Add the remaining characters from the "right" string
while (rightIndex < sortedRight.Length)
{
char nextChar = sortedRight[rightIndex++];
if (lastChar == nextChar) continue;
theResult.Append(nextChar);
lastChar = nextChar;
}
theResult.Append(sortedRight, rightIndex, sortedRight.Length - rightIndex);
return (theResult.ToString());
}
我希望这更有意义。
答案 2 :(得分:1)
您不需要2个char数组。 System.String数据类型有一个按位置的内置索引器,它从该位置返回char,因此您可以从0循环到(String.Length - 1)。如果您对速度比对优化存储空间更感兴趣,那么您可以为其中一个字符串创建一个HashSet,然后创建一个包含最终结果的第二个HashSet。然后迭代遍历第二个字符串,针对第一个HashSet测试每个char,如果它存在则将其添加到第二个HashSet。最后,您已经拥有一个包含所有交叉点的单个HashSet,并且自己保存在Hashtable中运行的通道,以查找具有非零值的HashSet。
编辑:我在关于根本不想使用任何内置容器的所有评论之前输入了这个
答案 3 :(得分:1)
这是我将如何做到这一点。它仍然是O(N)并且它不使用哈希表,而是使用长度为26的一个int数组。(理想情况下)
仍为O(N)且仅有26个整数的额外空间。
当然,如果您不仅限于较低或大写字符,则可能需要更改数组大小。
答案 4 :(得分:0)
“每个字母最多代表一次”
我假设这意味着你只需要知道交叉点,而不是它们发生了多少次。如果是这样,那么您可以通过使用yield来减少算法。而不是存储计数并继续迭代第二个字符串以寻找其他匹配,您可以在那里产生交集,并继续从第一个字符串开始下一个可能的匹配。