在O(1)空间和O(n)时间的数组中将相同类型的元素组合在一起

时间:2019-06-01 13:55:10

标签: c++ arrays algorithm

这是《编程访谈》一书中的一个问题: 题: 给定n个对象的数组,它们的键具有四个值,请对该数组重新排序,以使具有相同类型的对象一起出现。使用O(1)的额外空间和O(n)的时间。

我无法为三个以上的组构想一个主意(荷兰国旗问题)。任何帮助将不胜感激。

例如a [6] = {1,2,3,4,3,1};那么结果应该是{1,1,2,3,3,4}或以任何顺序排列,只有数字分组才有意义(即,结果不必按升序排列)

3 个答案:

答案 0 :(得分:4)

要使具有相同颜色的标记组合在一起,我们可以使用一个指针变量,并将所有具有当前标记的元素交换到左侧,并对每个后续标记重复此操作。最后,我们将所有4个标志分组在一起。空间复杂度为O(1),时间复杂度为O(标志数* n)。由于您的案例的标记为4,因此它将为O(4 * n)= O(n)。

#include <iostream>
using namespace std;

int main() {

    int a[] = {1,2,3,4,3,1,2,3,3,4};
    int size = sizeof(a) / sizeof(int);
    int ptr = 0;

    for(int flag=1;flag <= 4;++flag){
        for(int i=ptr;i<size;++i){
            if(a[i] == flag){
                swap(a[i],a[ptr++]);
            }
        }
    }

    for(int i=0;i<size;++i){
        cout<<a[i]<<" ";
    }

}

答案 1 :(得分:0)

O(n)DNF解从最低和最高索引开始形成两个集合,并且知道在它们之间某个地方形成的第三集合是同质的,因此不需要进一步处理。

如果将集合的数量增加到四个或更多,您仍然可以在同一“精神”中形成顶部和底部集合,因此在O(n)时间内,但是中间部分仍然混合在一起,它具有再次检查。这就是为什么它不再是“纯” O(n)的原因。

int a[] = { 1,2,3,4,3,1,2,3,3,4 };
int size = sizeof(a) / sizeof(int);

int bottom = 0, top = size - 1;
for (int bottomband = 1, topband = 4; topband > bottomband; bottomband++, topband--) {
    int i = bottom;
    while (i <= top) {
        if (a[i] == bottomband) {
            swap(a[i], a[bottom]);
            i++;
            bottom++;
        }
        else if (a[i] == topband) {
            swap(a[i], a[top]);
            top--;
        }
        else
            i++;
    }
}

for (int i = 0; i<size; ++i) {
    cout << a[i] << " ";
}

您可以识别出内部的“经典” DNF循环(当topband从3开始时,它就成为原始算法)。 a[]来自其他解决方案,以实现可比性(例如将计数器放入内部循环等)。

答案 2 :(得分:0)

让 unik_elems 数组包含可以进行比较的不同元素。即我们可以将 <> 与它们一起使用。例如[1,2,3,4]。 所以这里如果这些是 4 个不同的元素,那么我们可以首先选择主元为 2 并在 2 的左侧将 1 组,然后我们将主元更改为 3,将 2 组在 3 的左侧,因为我们已经分组了0,我们将获得未分组数组开始时的索引。这样我们就可以将主元更改为 4。假设我们首先对提供给我们的 4 个不同元素进行排序。

nums = [1,4,3,2,2,3,4,1,3,2,4,1,3,2,4,1]
unclassified = 0
unik_elems = [1,2,3,4]
for pivot_idx in range(1, len(unik_elems)):
    pivot = unik_elems[pivot_idx]
# we start the array from the index from where the elements are unclassified.
# Hence, when selecting 3 as pivot in this example, the elements on the left
# of unclassified will be 1 and hence wont we touched when we use 3 as the pivot.
    for idx in range(unclassified, len(nums)):
        if nums[idx] < pivot:
            nums[idx], nums[unclassified] = nums[unclassified], nums[idx]
            unclassified += 1

时间复杂度 = O(N),因为我们有 4 个不同的元素,所以这将是 3 遍解决方案。