from https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/04.03.md
题目描述
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
考虑到这个问题本身的特殊性,我们可以在遍历数组的时候保存两个值:一个candidate,用来保存数组中遍历到的某个数字;一个nTimes,表示当前数字的出现次数,其中,nTimes初始化为1。当我们遍历到数组中下一个数字的时候:
- 如果下一个数字与之前candidate保存的数字相同,则nTimes加1;
- 如果下一个数字与之前candidate保存的数字不同,则nTimes减1;
- 每当出现次数nTimes变为0后,用candidate保存下一个数字,并把nTimes重新设为1。 直到遍历完数组中的所有数字为止。
举个例子,假定数组为{0, 1, 2, 1, 1},按照上述思路执行的步骤如下:
- 1.开始时,candidate保存数字0,nTimes初始化为1;
- 2.然后遍历到数字1,与数字0不同,则nTimes减1变为0;
- 3.因为nTimes变为了0,故candidate保存下一个遍历到的数字2,且nTimes被重新设为1;
- 4.继续遍历到第4个数字1,与之前candidate保存的数字2不同,故nTimes减1变为0;
- 5.因nTimes再次被变为了0,故我们让candidate保存下一个遍历到的数字1,且nTimes被重新设为1。最后返回的就是最后一次把nTimes设为1的数字1。
思路清楚了,完整的代码如下:
//a代表数组,length代表数组长度
int FindOneNumber(int* a, int length)
{
int candidate = a[0];
int nTimes = 1;
for (int i = 1; i < length; i++)
{
if (nTimes == 0)
{
candidate = a[i];
nTimes = 1;
}
else
{
if (candidate == a[i])
nTimes++;
else
nTimes--;
}
}
return candidate;
}