有2个字符数组。两个阵列都具有相同的大小和互相混杂的形式。
例如:
char a[] = {'a', 'b', 'a', 'b', 'c', 'a', 'b', 'a', 'b', 'c' };
char b[] = {'a', 'a', 'b', 'b', 'c', 'c', 'b', 'b', 'a', 'a' };
我想在数组 a 中找到数组 b 元素的不同位置(从1开始索引),即:1,3,2,4, 5,10,7,9,6,8,对于这个例子。
我实施了以下蛮力方法 O ( n 2 ):
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (b[i] == a[j])
{
cout << j + 1 << " ";
a[j] = '\0';
break;
}
}
}
C ++中是否有任何方法可以将时间复杂度降低到 O ( n * log( n ))甚至更少?
答案 0 :(得分:2)
它可以以O(n)存储器的代价减少到O(n)时间。
你应该创建二维数组。它的第一个维度将是所有字符(总共256 = 2 ^ 8个索引,因为sizeof(char)= 1个字节),第二个维度将超过你数组的n个元素。
所以,如果你有
char a[n] = ...;
char b[n] = ...;
你应该分配
int c[256][n]; // O(n) memory
int s[256]; // O(1) memory
int e[256]; // O(1) memory
并用零填充它们。您可以使用e [i]作为 a 中代码 i 的字符数的计数器。在c [i] [0],c [i] [1],...中,您可以在 a 数组中存储代码 i 的字符的实际位置。
第一步是迭代数组 a ,每次
您可以使用数组 s 来存储已打印的符号位置数(s [j]是代码 j 的打印字符数)。第二步是迭代 b ,每次
每个步骤消耗O(n)时间,因此总时间复杂度为O(n)。值得注意的是,使用随机方法(如哈希表,你必须考虑命中概率)这种复杂性不是意味着的情况。 最差情况下,这种复杂性将是相同的。
答案 1 :(得分:1)
您可以简单地将索引插入到由元素值键入的多图中,然后迭代另一个数组,找到您需要的第一个索引,然后将其从地图中删除。应该是O(n log n):
std::multimap<char, int> charmap;
for (unsigned i = 0; i < sizeof a; i++) {
charmap.emplace(a[i], i);
}
for (char c : b) {
auto it = charmap.find(c);
std::cout << it->second + 1 << " ";
charmap.erase(it);
}
答案 2 :(得分:0)
您可以拥有一个哈希表,并且在每个存储桶中都有一个列表。该列表将包含b []的索引,在该索引处出现该字符。
取b []中的每个元素,比如b [i],找到散列表中的索引等于b [i]的列表(在你的情况下将是'a'或'b'或'c' )。如果没有列表,请创建值为i + 1的列表。如果找到列表,请将i + 1添加到列表的末尾
在您的示例中,插入完成后
当您处理条目时,使用列表中的第一个元素并从列表中删除第一个元素。 在上面的例子中,
处理完第一个条目'a'后 - 您将给出1,并从索引'a'的列表中删除1。现在
处理完第二个条目'b'后,你将给出3并从索引'b'的列表中删除3。现在
这是O(N)? (假设你有双重链表)
答案 3 :(得分:0)
修改强> 我更喜欢@ user2079303的答案。相同的概念,更容易实现。
反向查找的具体实现。您将看到前两个循环是开销。 unordered_map
基本上是&#34;哈希表&#34;在另一个答案中建议。
auto it
是一个迭代器,first
是索引,second
是值(在我们的例子中是queue
)。令人困惑的是,作为反向查找,&#34;索引&#34;也是你考虑的价值(反之亦然,每个&#34;值&#34;在队列上是a
的索引。
我使用了一个队列,因为您只想使用每个索引一次(因此pop
相当于将值设置为\0
)。
我认为理解它的最好方法是在调试器中逐步完成它。
#include <unordered_map>
#include <queue>
#include <memory>
#include <iostream>
using namespace std;
int main()
{
char a[] = { 'a', 'b', 'a', 'b', 'c', 'a', 'b', 'a', 'b', 'c' };
char b[] = { 'a', 'a', 'b', 'b', 'c', 'c', 'b', 'b', 'a', 'a' };
unordered_map<char, shared_ptr<queue<int>>> reverseIndex;
//create a queue for each unique char
for (int i = 0; i < 10; ++i)
{
auto it = reverseIndex.find(a[i]);
if (it == reverseIndex.end())
{
reverseIndex.emplace(a[i], make_shared<queue<int>>());
}
}
//put the indexes as *values* into our unordered_map vectors
for (int i = 0; i < 10; ++i)
{
auto it = reverseIndex.find(a[i]);
it->second->push(i);
}
//perform the actual work
for (int i = 0; i < 10; ++i)
{
auto it = reverseIndex.find(b[i]);
cout << it->second->front()+1 << "\n";
//you'll need to push the value back onto the queue for multiple uses of reverseIndex: it->second->push(it->second->front());
it->second->pop();
}
return 0;
}