【问题标题】:Sort the Array and move all the repeated Elements to End对数组进行排序并将所有重复的元素移动到结尾
【发布时间】:2016-08-22 16:40:16
【问题描述】:

我在最近的采访中遇到了这个问题。

给定一个数组,我需要对数组进行排序,所有重复的元素都应该在最后。

示例: 输入:{7,4,2,3,3,5,3,11,9,2}

由于 2 & 3 是重复的元素,它们应该出现在 Array 的末尾。

输出:{4,5,7,9,11,2,2,3,3,3}

我可以随意使用任何其他数据结构。没有限制。

【问题讨论】:

  • 您需要简单的解决方案还是超级高效的解决方案?如果您需要效率,还请提供输入限制(数字数量和大小)。
  • @Blaž Zupančič。没有约束。我在排序和散列的帮助下给出了解决方案。但他并不满足。他需要一个具有排序和最少操作的解决方案。
  • 你确定输出不应该是 {2,3,4,5,7,9,11,2,3,3} 吗?
  • @m69。不。如果元素重复,所有它的出现都应该在最后。
  • 所以你不需要排序,而是你需要安排事情,使单个项目首先出现在列表中,然后是重复的项目。你的输出可以是{7,4,5,11,9,3,3,2,2}吗?也就是说,只要单个在左边,重复在右边,项目的顺序是否重要?

标签: algorithm sorting data-structures


【解决方案1】:
CREATE_ARRAY repeated, unique
SORT inputArray
ADD MINIMAL_POSSIBLE_VALUE TO inputArray
TRAVERSE inputArray i=index (from 2nd element to last):
   IF inputArray[i-1] == inputArray[i]:
      2X: ADD inputArray[i] TO repeated
      i++
      WHILE i < LENGTH(inputArray) - 1 and inputArray[i-1] == inputArray[i]:
         ADD inputArray[i] TO repeated
         i++
   ELSE:   
      ADD inputArray[i-1] TO unique
PRINT MERGED(unique, repeated)

您将对数组进行排序,以便重复值形成补丁。然后,您将数组分配给唯一值数组和重复值数组并打印它们。

第三行ADD MINIMAL_POSSIBLE_VALUE TO inputArray 只是向数组中添加了一个虚拟元素,该元素永远不会被打印,但会为您节省一些 IF 语句。

// algorithm
function algorithm(input) {
  input.sort(function(a, b) { return a - b });
  input.push(Number.MIN_VAL);
  var repeated = [], unique = [];
  for (var i = 1; i < input.length; i++) {
    if (input[i - 1] == input[i]) {
      repeated.push(input[i], input[i]);
      i++;
      while (i < input.length - 1 && input[i - 1] == input[i]) {
        repeated.push(input[i]);
        i++;
      }
    } else {
      unique.push(input[i - 1]);
    }
  }
  return unique.concat(repeated);
}

// driver
inputBox = document.getElementById('input-box');
outputBox = document.getElementById("output-box");
inputBox.addEventListener("keyup", function() {
  outputBox.innerHTML = algorithm(inputBox.value.split(/[\s,]+/).map(Number));
});
<input id="input-box">
<div id="output-box"></div>

【讨论】:

  • 我认为这会奏效。我很好奇我们能否就地解决这个问题?
【解决方案2】:

C#中使用List的排序方法的解决方案

        static void Main(string[] args)
    {
        List<int> list = new List<int> { 7, 4, 2, 3, 3, 5, 3, 11, 9, 2, 5 };

        List<int> tmp = new List<int> { };
        List<int> rep = new List<int> {};

        //sorting the list
        list.Sort();

        for (var i = 0; i < list.Count(); i++) 
        {
            int cantidad = list.LastIndexOf(list[i]) - list.IndexOf(list[i]);
            if ( cantidad != 0)
            {
                //found repetitions
                rep.AddRange(list.GetRange(list.IndexOf(list[i]), cantidad + 1));
                i += cantidad;
            }
            else tmp.Add(list[i]);
        }
        tmp.AddRange(rep);

        foreach (int data in tmp)
            Console.WriteLine(data);

        Console.ReadLine();
    }

使用 C# 手动排序的解决方案

        static void Main(string[] args)
    {
        List<int> list = new List<int> { 7, 4, 2, 3, 3, 5, 3, 11, 9, 2 };

        List<int> tmp = new List<int> {};
        List<int> rep = new List<int> {};

        foreach (int data in list)
        {
            if (tmp.Count() > 0)
            {
                int posicion = -1;
                bool bandera = false;
                for (var i=0; i < tmp.Count(); i++)
                {
                    //searching a repetition
                    if (tmp[i] == data)
                    {
                        tmp.RemoveAt(i);
                        //adding to the repeated list at the end or in a determined position
                        for (var j = 0; j < rep.Count(); i++)
                        {
                            if (rep[j] > data)
                            {
                                bandera = true;
                                rep.Insert(j, data); //the one that was deleted
                                rep.Insert(j, data); //the one at the original list
                                break;
                            }
                        }
                        if (!bandera)
                        {
                            bandera = true;
                            rep.Add(data); //the one that was deleted
                            rep.Add(data); //the one at the original list
                        }
                        break;
                    }
                    //saving the position to be inserted
                    if (tmp[i] > data)
                    {
                        posicion = i;
                        break;
                    }
                }
                //was not a repetition
                if (!bandera)
                {
                    bool banderaRep = false;
                    //searching in the repeated list
                    for (var i = 0; i < rep.Count(); i++)
                    {
                        if (rep[i] == data)
                        {
                            banderaRep = true;
                            rep.Insert(i, data);
                            break;
                        }
                    }
                    //was not in the repeated list
                    if (!banderaRep)
                    {
                        if (posicion == -1)
                            tmp.Add(data);
                        else
                            tmp.Insert(posicion, data);
                    }
                }
            }
            else
                tmp.Add(data);
        }
        //join
        tmp.AddRange(rep);

        foreach (int data in tmp)
            Console.WriteLine(data);

        Console.ReadLine();
    }

【讨论】:

  • 什么是“排序类”?
  • 对不起,不是类,方法,已经更正了。第二种解决方案是手动提出排序过程,不使用语言的好处
【解决方案3】:

使用地图数据结构的解决方案,不是一个非常有效的解决方案,但它仍然有效:

1> 遍历地图中数字的向量计数频率
2> 遍历地图(元素将按排序顺序)推送一个向量中的唯一元素和另一个向量中的重复元素
3> 推入排序后的数组中重复的元素

C++ 代码

vector<int> sortUnique(const vector<int> & nums) {

// Step 1
map<int, int> numFreq;
for (auto it : nums) {
    if (numFreq.count(it) == 0) {
        numFreq[it] = 1;
    }
    else {
        numFreq[it]++;
    }
}

// Step 2
vector<int> sorted;
sorted.reserve(nums.size());
vector<int> repeated;
repeated.reserve(nums.size());
for (auto it : numFreq) {
    if (it.second == 1) {
        sorted.push_back(it.first);
    }
    else {
        for (int i = 0; i < it.second; i++) {
            repeated.push_back(it.first);
        }
    }
}
// Push repeated elements at the end
for (auto it : repeated) {
    sorted.push_back(it);
}
return sorted;
}

【讨论】:

    【解决方案4】:

    我将使用 Swift 3(beta 3)来描述您的问题的高级实现。

    let list = [7,4,2,3,3,5,3,11,9,2]
    let countedSet = NSCountedSet(array: list)
    let singles = list.filter { countedSet.count(for: $0) == 1 }
    let duplicates = list.filter { countedSet.count(for: $0) > 1 }
    let res = singles.sorted() + duplicates.sorted()
    

    第 2 行

    这个类创建一个索引,它与每个值关联它的出现次数。

    第 3 行和第 4 行

    我在这里过滤原始数组。我将仅出现 1 次的值放入 singles 并将出现多次的值放入 duplicates

    第 5 行

    最后我对singlesduplicates 进行排序并将它们连接起来

    【讨论】:

      【解决方案5】:

      您可以使用具有相关计数的值字典来执行此操作。你没有指定语言,所以我给你一些伪代码。

      注意这不会导致排序输出。

      首先,扫描数组并创建值和计数字典:

      dict = create new dictionary
      for each item in array
          if dict contains item
              increase count for that item in the dictionary
          else
              add item to dictionary with count of 1
      

      现在创建两个索引:一个从 0 开始,另一个从 (array.length - 1) 开始。对于字典中的每一项,如果是单项,则写在数组的最前面。否则在数组的后面写count 项。像这样:

      frontIndex = 0
      backIndex = array.Length - 1
      for each item in dictionary
          if item.count == 1
              array[frontIndex] = item
              frontIndex = frontIndex + 1
          else
             for i = 0 to item.Count-1
                 array[backIndex-i] = item
             backIndex = backIndex - item.Count
      

      构建字典的时间是 O(n),重新填充数组的时间是 O(n)。额外的空间是 O(n)。

      【讨论】:

      • dictionary 不保证项目将按排序顺序排列,因此在 for each 循环的第二部分中,项目不会按排序顺序出现。我在我的解决方案中使用了 BST,以确保对项目进行排序。
      • @RandomGuy:OP 的示例没有显示已排序的项目,所以我没有对它们进行排序。
      • 我的意思是,在将项目写入数组的前面时,您假设以排序顺序检索项目,这是不正确的。
      • @RandomGuy:不,我不假设这些项目是按排序顺序排列的。我不在乎输出是否已排序,因为 OP 的示例输出未排序。
      • @RandomGuy:所以我错了:OP 确实希望对输出进行排序。我必须想出最好的方法来做到这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-25
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 1970-01-01
      • 2016-04-27
      相关资源
      最近更新 更多