题意分析:
(1)给出M*N的像素矩阵,矩阵的每个元素代表24比特的RGB值,找出这个矩阵中总个数超过一半的像素值(一定存在)
(2)找出一组数中个数超过一半的数,以下有两种常见思路:
①有一种思路是统计每个数出现的次数:先开辟大小为2^24+1的计数数组count,初始化为0,然后依据数组下标作为元素值统计数组中每个元素出现的次数。然后再寻找出现次数最多的那个数。这样做还没等统计完。第二个测试案例就已经超时,并且可能会由于开辟辅助空间过大造成溢出段错误。
②由于这种超过数组长度一半的数一定存在,因此对数组排序后,无论数组多长,处于中间的数一定是最多的那个数,因此方案二就是先对数组排序,然后取中间的那个数,但是很遗憾,如果对数组排序,依然会造成超时
既然以上两种思路都不能达到最佳效率,我们只能再从问题本身去挖掘其他的隐含信息了:
(3)以上两种思路都是等矩阵输入结束之后进行处理的,看来此题的突破口就是在边输入边处理了。再细想因为总数超过一半,我们考虑这样一种情形:维护一个深度为M*N的栈,为了维护操作的一致性,栈底的元素设置为-1,当输入的数与栈顶的数相同的时候,就入栈,如果不相同就出栈一个元素,这样做的意图就是说找到两个不相同的元素“抵消掉”,因为最终要求的数总数超过一半,因此无论怎么抵消,它至少还剩余一个元素,而其他的元素肯定已经抵消没了,那么最后直接输出栈顶的元素就是最终结果。
(4)进一步简化(3)的思路,将维护一个栈简化为维护一个变量初始化为-1,以及这个变量当前的“剩余个数”,初始化为1,当输入元素和这个变量不同的时候,剩余个数-1,相同时候+1,当剩余个数=0的时候,就重新初始化变量为当前输入元素,并且剩余个数=1.
可能坑点:
(1)这题虽然题意简单,但是却暗藏陷阱,并不是很容易能想到复杂度为O(n)的算法,暴力和排序一定超时
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int M,N,i=0;
scanf("%d%d",&M,&N);
int temp,num=-1,cnt=1;
while(i<N*M)
{
scanf("%d",&temp);
if(temp==num)cnt++;
else cnt--;
if(cnt==0)
{
num=temp;
cnt=1;
}
i++;
}
printf("%d\n",num);
return 0;
}