我已经读过这个问题 Find the most common entry in an array
jon双向飞碟的回答只是让人心旷神情...... :)
现在我正在尝试解决这个问题,找到一个在数组中发生超过n / 3次的元素。
我很确定我们不能应用相同的方法,因为可能有2个这样的元素会发生超过n / 3次并且会给出错误的计数警报。所以我们可以调整jon周围的任何方式双向飞碟为此工作的答案..?
或者有任何解决方案将以线性时间运行吗?
答案 0 :(得分:22)
Jan Dvorak's answer可能是最好的:
最后,对阵列进行第二次传递以检查候选者是否确实具有所需的计数。您链接的问题不允许这样做,但我不知道如何针对此修改版本避免使用此问题。如果某个值超过n / 3次,那么它将位于一个插槽中,但您不知道它是哪一个。
如果问题的此修改版本保证两个值超过n/3
个元素(通常k-1
个值超过n/k
那么我们就不需要第二遍了。但是当原始问题有k=2
和1个保证多数时,我们无法知道我们是否应该"将其概括为保证1个这样的元素或保证k-1
。保证越强,问题就越容易。
答案 1 :(得分:3)
您可以使用Selection algorithm查找n / 3位置和2n / 3中的数字。
n1=Selection(array[],n/3);
n2=Selection(array[],n2/3);
coun1=0;
coun2=0;
for(i=0;i<n;i++)
{
if(array[i]==n1)
count1++;
if(array[i]==n2)
count2++;
}
if(count1>n)
print(n1);
else if(count2>n)
print(n2);
else
print("no found!");
答案 2 :(得分:2)
在第五行,if
语句应该再检查一次:
if(n!=b && (cnt1 == 0 || n == a))
答案 3 :(得分:0)
如果数组中有n个元素,并且假设在最坏的情况下仅重复1个元素n / 3次,则选择一个数字而不是重复n / 3次的概率为( 2n / 3)/ n是1/3,因此,如果我们从大小为'n'的数组中随机选择N个元素,那么最终选择n / 3次重复数的概率将至少为1-(2 / 3)^ N。如果我们用99.99%的概率获得成功,则对于任何“ n”值,我们将获得N = 23。
因此,只需从列表中随机选择23个数字并计算它们的出现次数,如果我们得到的计数大于n / 3,我们将返回该数字,如果我们在随机检查了23个数字后没有得到任何解决方案,则返回- 1;
该算法本质上是O(n),因为值23不依赖于n(list的大小),因此在算法最坏的情况下,我们只能遍历数组23次。
面试位(C ++)上的接受代码:
int n=A.size();
int ans,flag=0;
for(int i=0;i<23;i++)
{
int index=rand()%n;
int elem=A[index];
int count=0;
for(int i=0;i<n;i++)
{
if(A[i]==elem)
count++;
}
if(count>n/3)
{
flag=1;
ans=elem;
}
if(flag==1)
break;
}
if(flag==1)
return ans;
else return -1;
}
答案 4 :(得分:0)
我使用以下Python解决方案来讨论算法的正确性:
class Solution:
"""
@param: nums: a list of integers
@return: The majority number that occurs more than 1/3
"""
def majorityNumber(self, nums):
if nums is None:
return None
if len(nums) == 0:
return None
num1 = None
num2 = None
count1 = 0
count2 = 0
# Loop 1
for i, val in enumerate(nums):
if count1 == 0:
num1 = val
count1 = 1
elif val == num1:
count1 += 1
elif count2 == 0:
num2 = val
count2 = 1
elif val == num2:
count2 += 1
else:
count1 -= 1
count2 -= 1
count1 = 0
count2 = 0
for val in nums:
if val == num1:
count1 += 1
elif val == num2:
count2 += 1
if count1 > count2:
return num1
return num2
首先,我们需要证明索赔A:
声明A :考虑一个列表C
,其中包含多数数m
,出现次数floor(n/3)
次。从C
中删除3个不同的数字后,我们得到C'
。 m
是C'
的多数数。
证明:使用R
表示m
在C
中的出现次数。我们有R > floor(n/3)
。 R > floor(n/3)
=> R - 1 > floor(n/3) - 1
=> R - 1 > floor((n-3)/3)
。使用R'
来表示m
中C'
的出现次数。并使用n'
表示C'
的长度。由于删除了3个不同的数字,因此我们有R' >= R - 1
。 n'=n-3
很明显。我们可以有R' > floor(n'/3)
中的R - 1 > floor((n-3)/3)
。因此m
是C'
的多数数。
现在让我们证明loop 1
的正确性。将L
定义为count1 * [num1] + count2 * [num2] + nums[i:]
。使用m
表示多数数。
不变
多数m
在L
中。
初始化
第一次注册开始时,L
是nums[0:]
。因此,不变性是微不足道的。
维护
if count1 == 0
分支:在迭代之前,L
是count2 * [num2] + nums[i:]
。迭代之后,L
是1 * [nums[i]] + count2 * [num2] + nums[i+1:]
。换句话说,L
不变。这样就保持不变。
if val == num1
分支:在迭代之前,L
是count1 * [nums[i]] + count2 * [num2] + nums[i:]
。迭代之后,L
是(count1+1) * [num[i]] + count2 * [num2] + nums[i+1:]
。换句话说,L
不变。这样就保持不变。
f count2 == 0
分支:与条件1相似。elif val == num2
分支:与条件2相似。else
分支:在这种情况下,nums[i]
,num1
和num2
彼此不同。迭代之后,L
是(count1-1) * [num1] + (count2-1) * [num2] + nums[i+1:]
。换句话说,从count1 * [num1] + count2 * [num2] + nums[i:]
中移出了三个不同的数字。根据声明A,我们知道m
是L
的多数数。因此不变量得以保持。终止
当循环终止时,nums[n:]
为空。 L
是count1 * [num1] + count2 * [num2]
。
因此,当循环终止时,多数数为num1
或num2
。