确定是否有一半以上的数组在不同的数组中重复

时间:2013-02-07 21:15:15

标签: algorithm data-structures

我正在查看以下question from Glassdoor

给定N个信用卡,确定其中一半以上是否属于同一个人/所有者。你所拥有的只是一系列信用卡号码,以及像isSamePerson(num1,num2)这样的api调用。

很明显如何在O(n ^ 2)中进行,但是一些评论者表示可以在O(n)时间内完成。它甚至可能吗?我的意思是,如果我们有一系列信用卡号码,其中一些数字被重复,那么这个说法是有道理的。但是,我们需要为每个信用卡号码进行API调用以查看其所有者。

我在这里缺少什么?

5 个答案:

答案 0 :(得分:14)

算法如下:

如果一个项目(此处为一个人)占多数,那么如果您将不相等的项目(按任何顺序)组合在一起,此项目将被遗留。

  • 从空的候选插槽开始
  • 每件商品
    • 如果候选插槽为空(count = 0),请将其放在那里。
    • 否则,如果它等于插槽中的项目,则递增其计数。
    • Else减少该位置的计数(弹出一个项目)。
  • 如果候选名单上没有任何内容,则没有明显的多数。否则,
  • 计算候选人的出现次数(第二次通过)。
  • 如果出现的次数超过50%,则宣布为胜利者,
  • 否则没有多数。

请注意,如果阈值低于50%,则无法应用此值(但应该可以通过保持两个,三个......候选插槽并仅弹出一个独特的插槽来适应阈值33%,25%......三倍,四倍......)。

这也适用于信用卡的情况:您只需比较两个元素(人)的相等性(通过API调用),以及一个能够容纳元素总数的计数器。

时间复杂度:O(N)
空间复杂度:O(1) +输入
API调用:最多2N-1:每次传递一次,第一次传递中第一个元素没有api调用。

答案 1 :(得分:3)

设x1,x2,...,xn为信用卡号。

请注意,由于超过一半属于同一个人,如果您考虑两个相邻的数字,则至少有一对将属于同一个人。

如果考虑所有对(x1,x2),(x3,x4)....并考虑两个元素属于同一个人的对子集,则大多数同一对人属于该人谁拥有大多数卡在第一位。因此,对于每个同一对人保持一个卡号和非同一人对丢弃两者。递归执行此操作并返回最后剩余的同一对人。

你需要进行最多n次比较。

注意:如果n为奇数,请保留未配对的数字。

为什么会这样:假设n是偶数而A人拥有n / 2 + 1张卡。在最坏的情况下,你只有一对,其中两张牌都归A所有。在这种情况下,其他对中没有一对由同一个人拥有(其他一对包含一张A卡和一张其他人的卡)。

现在,要创建一对匹配的B(非A人),您还必须创建一对B。因此,在每种情况下,大多数匹配对都归A所有。

答案 2 :(得分:2)

我没有评论的声誉。 Jan Dvorak讲述的方法被称为摩尔的投票算法(流计数算法)。这是代码。

int majorityElement(int* nums, int numsSize) {
int count =0, i, majorityElement;
/*Moore's voting algorithm Order(n), Auxiliary space: Order(1)*/
/*step:1-To get candidate for the majority element*/
for(i=0; i < numsSize; i++)
{
    if(count==0)
        majorityElement = nums[i];
    if(nums[i]==majorityElement)
        count++;
    else
        count--;
}
/*Step:2- To check whether this candidate occurs max no. of times */
count =0;
for(i=0; i<numsSize; i++)
{
    if(nums[i]==majorityElement)
        count ++;
}
if(count>numsSize/2) /*It can only be applied for majority check */
    return majorityElement; 
return -1;}

答案 3 :(得分:0)

问题是要找出数组中的多数元素。我会用的 Boyer-Moore多数投票算法。我是用HashMap做的。

public class majorityElement1 {
public static void main(String[] args) {
    int a[] = {2,2,2,2,5,5,2,3,3,3,3,3,3,33,3};
    fix(a);

}

public static void fix(int[] a ) {
 Map<Integer,Integer> map = new HashMap<>();

 for(int i = 0 ; i<a.length ; i++) {
     int r  = a[i];
     if(!map.containsKey(r)) {
         map.put(r, 1);
     }else {

         if(map.get(r) +1 >= a.length/2) {
             System.out.println("majority element => "+ r);
             return ;
             }else {
                 map.put(r,map.get(r) +1);
             }

     }//else1
 }//for
    }
}

输出为3。

答案 4 :(得分:-1)

完成一次通过:

  • 从数组的第二个索引开始,先说i = 1。
  • 最初计数= 1。
  • 调用isSamePerson(a [i],a [i-1]),其中数组a []包含信用卡号。
  • 如果返回值为正,请执行count ++和i ++
  • 如果返回值为0且count == 1,则为i ++
  • 如果返回值为0且count> 1,则执行count--和i ++
  • 如果i!=(n-1),请转到步骤3,其中n是卡片数。
  • else如果在数组计数结束时> 1,那么有超过一半的卡属于一个人
  • 否则没有超过50%的明显多数。

我希望这是可以理解的,编写代码会很容易。

时间复杂度 - O(N)
API调用次数= N-1
空间复杂度 - O(1)