C++ 使用数组并将副本移动到末尾

C++ 使用数组并将副本移动到末尾,c++,arrays,sorting,duplicates,theory,C++,Arrays,Sorting,Duplicates,Theory,我在一次采访中得到了这个问题,最后被告知有一种更有效的方法来解决这个问题,但我仍然无法找到答案。您正在向函数传递一个整数数组和一个表示数组大小的整数。在数组中有很多数字,其中一些重复出现,例如1,7,4,8,2,6,8,3,7,9,10。您希望获取该数组并返回一个数组,其中所有重复的数字都放在数组的末尾,这样上面的数组将变成1,7,4,8,2,6,3,9,10,8,7。我使用的数字并不重要,而且我不能使用缓冲区数组。我打算使用BST,但必须保持数字的顺序(除了重复的数字)。我不知道如何使用哈希表

我在一次采访中得到了这个问题,最后被告知有一种更有效的方法来解决这个问题,但我仍然无法找到答案。您正在向函数传递一个整数数组和一个表示数组大小的整数。在数组中有很多数字,其中一些重复出现,例如
1,7,4,8,2,6,8,3,7,9,10
。您希望获取该数组并返回一个数组,其中所有重复的数字都放在数组的末尾,这样上面的数组将变成
1,7,4,8,2,6,3,9,10,8,7
。我使用的数字并不重要,而且我不能使用缓冲区数组。我打算使用BST,但必须保持数字的顺序(除了重复的数字)。我不知道如何使用哈希表,所以我最终使用了double for循环(我知道是n^2)。我将如何更有效地使用C++。不寻找代码,只想知道如何做得更好。

我这样做的方法是创建一个两倍于原始数组大小的数组,并创建一组整数

然后循环遍历原始数组,将每个元素添加到集合中,如果已经存在,则将其添加到新数组的下半部分,否则将其添加到新数组的上半部分

最后,您将得到一个如下所示的数组:(使用您的示例)

1,7,4,8,2,6,3,9,10,8,7,-

然后我将再次循环原始数组,使每个点等于下一个非空位置(或0'd或您决定的任何位置)

这将使原始阵列变成您的解决方案

结果是O(n),这是我能想到的效率

Edit: since you can not use another array, when you find a value that is already in the
set you can move every value after it forward one and set the last value equal to the
number you just checked, this would in effect do the same thing but with a lot more operations.

我将使用一个额外的映射,其中键是数组中的整数值,值是一个在开始时设置为0的整数。现在我将遍历数组,如果键已经在映射中,则增加映射中的值。 最后,我将再次遍历数组。当数组中的整数在映射中的值为1时,我不会更改任何内容。当它在映射中的值为2或更多时,我会将数组中的整数与最后一个整数交换

这将导致运行时为O(n*log(n))

void remove\u dup(int*data,int count){
int*L=data;//放置下一个唯一编号的位置
int*R=data+count;//位置到位置下一个重复编号
std::无序集已找到(计数);//跟踪所看到的内容

对于(int*cur=data;cur如果您知道整数值的界限,
B
,以及整数数组的大小,
SZ
,则可以执行以下操作:

  • B
    元素创建一个布尔值数组,初始化为0
  • 使用
    SZ
    元素创建整数的结果数组
    result
  • 创建两个整数,一个用于
    前\u pos=0
    ,一个用于
    后\u pos=SZ-1
  • 在原始列表中迭代:
    • 将整数变量
      val
      设置为当前元素的值
    • 如果[val]
  • 之前的
    seen\u设置为1,则将数字置于
    result[back\u pos]
    处,然后递减
    back\u pos
  • 如果[val]
  • 之前的
    seen_未设置为1,则将数字置于
    result[front_pos]
    处,然后递增
    front_pos
    并将[val]
    之前的
    seen_设置为1
    
    完成对主列表的迭代后,所有唯一的数字将位于列表的前面,而重复的数字将位于列表的后面。有趣的是,整个过程是一次完成的。请注意,只有知道原始数组中出现的值的边界时,这才有效

    编辑:有人指出,所使用的整数没有边界,因此,与其将之前的
    视为包含
    B
    元素的数组初始化,不如将其初始化为
    映射,然后像往常一样继续。这应该会使您获得n*log(n)性能。

    包括和。

    如下所示:

    #include <algorithm>
    
    T * array = [your array];
    size_t size = [array size];
                                               // Complexity:
    sort( array, array + size );               // n * log(n) and could be threaded
                                               // (if merge sort)
    T * last = unique( array, array + size );  // n, but the elements after the last
                                               // unique element are not defined
    
  • arr
    是输入数组
  • seen
    是已经遇到的一组散列数字
  • l
    是将放置下一个唯一元素的索引
  • r
    是要考虑的下一个元素的索引
  • 因为您不是在寻找代码,所以这里有一个伪代码解决方案(恰好是有效的Python):


    我已经失去联系有一段时间了,但我可能会从这样的事情开始,看看它如何随着更大的输入而扩展。我知道你没有要求代码,但在某些情况下,它比解释更容易理解

    编辑:很抱歉,我错过了不能使用缓冲区数组的要求

    // returns new vector with dupes a the end
    std::vector<int> move_dupes_to_end(std::vector<int> input)
    {
        std::set<int> counter;
        std::vector<int> result;
        std::vector<int> repeats;
    
        for (std::vector<int>::iterator i = input.begin(); i < input.end(); i++)
        {
            if (counter.find(*i) == counter.end())
                result.push_back(*i);
            else
                repeats.push_back(*i);
            counter.insert(*i);
        }
    
        result.insert(result.end(), repeats.begin(), repeats.end());
    
        return result;
    }
    
    //返回以重复a结尾的新向量
    std::vector move_Dups_to_end(std::vector input)
    {
    设置计数器;
    std::向量结果;
    std::载体重复;
    对于(std::vector::iterator i=input.begin();i
    它很难看,但它满足了将副本移动到末端的要求(无缓冲区阵列)

    //警告,有些轻C++11
    无效重复结束(整数*arr,大小\u t cnt)
    {
    std::集k;
    自动结束=arr+cnt-1;
    自动最大值=arr+cnt;
    自动电流=arr;
    而(电流<最大值)
    {
    自动恢复=k.插入(*当前值);
    //第一次遇到
    如果(第二项决议)
    {
    ++咖喱;
    }
    其他的
    {
    //重复:
    标准:掉期(*当前,*结束);
    --结束;
    --最大值;
    }
    }
    }
    
    这可以通过迭代第一次更改的数组和标记索引来完成。 稍后,用下一个唯一值替换该标记索引值
    arr = [1,7,4,8,2,6,8,3,7,9,10]
    seen = set()
    l = 0
    r = 0
    while True:
      # advance `r` to the next not-yet-seen number
      while r < len(arr) and arr[r] in seen:
        r += 1
      if r == len(arr): break
      # add the number to the set
      seen.add(arr[r])
      # swap arr[l] with arr[r]
      arr[l], arr[r] = arr[r], arr[l]
      # advance `l`
      l += 1
    print arr
    
    [1, 7, 4, 8, 2, 6, 3, 9, 10, 8, 7]
    
    // returns new vector with dupes a the end
    std::vector<int> move_dupes_to_end(std::vector<int> input)
    {
        std::set<int> counter;
        std::vector<int> result;
        std::vector<int> repeats;
    
        for (std::vector<int>::iterator i = input.begin(); i < input.end(); i++)
        {
            if (counter.find(*i) == counter.end())
                result.push_back(*i);
            else
                repeats.push_back(*i);
            counter.insert(*i);
        }
    
        result.insert(result.end(), repeats.begin(), repeats.end());
    
        return result;
    }
    
    // warning, some light C++11
    void dup2end(int* arr, size_t cnt)
    {
       std::set<int> k;
       auto end = arr + cnt-1;
       auto max = arr + cnt;
       auto curr = arr;
    
       while(curr < max)
       {
          auto res = k.insert(*curr);
    
          // first time encountered
          if(res.second)
          {
             ++curr;
          }
          else
          {
             // duplicate:
             std::swap(*curr, *end);
             --end;
             --max;
          }
       }
    }
    
    public static void solve() {
                    Integer[] arr = new Integer[] { 1, 7, 4, 8, 2, 6, 8, 3, 7, 9, 10 };
            final HashSet<Integer> seen = new HashSet<Integer>();
            int l = -1;
    
            for (int i = 0; i < arr.length; i++) {
                if (seen.contains(arr[i])) {
                    if (l == -1) {
                        l = i;
                    }
                    continue;
                }
                if (l > -1) {
                    final int temp = arr[i];
                    arr[i] = arr[l];
                    arr[l] = temp;
                    l++;
                }
                seen.add(arr[i]);
            }
    
        }
    
    void move_duplicates_to_end(vector<int> &A) {
        if(A.empty()) return;
        int i = 0, tail = A.size()-1;
        while(i <= tail) {
            bool is_first = true;    // check of current number is first-shown
            for(int k=0; k<i; k++) { // always compare with numbers before A[i]
                if(A[k] == A[i]) {
                    is_first = false;
                    break;
                }
            }
            if(is_first == true) i++;
            else {
                int tmp = A[i]; // swap with tail
                A[i] = A[tail];
                A[tail] = tmp;
                tail--;
            }
        }