hdu1029 动态规划,一次遍历得到数列中出现次数过半的值

动态规划的思想。
因为要求数个数过半,所以如果存在,必只有一个。
若 a 为n个数中出现次数过半的数,则去掉这个数列的前k个数,当这k个数中不存在出现次数过半的数时,剩余n-k个数中出现次数过半的数仍是a。自己列个式子证明下就好。我们先称这样的k个数的前缀数列为k数列吧。存在过半的数就是非k数列。注意n只会为奇数。
所以,只要不断去掉数列的k数列,最终就一定会留下一个非k数列。
怎样判断一个前缀数列是k数列?
定义两个变量分别为ans、cnt。
ans记录当前前缀数列中出现次数过半的数,cnt记录它出现的次数超过当前前缀数列半数的多少。cnt=0时,表示ans出现次数等于半数;cnt=1时,表示ans出现次数=(m+1)/2+0;cnt=2时,出现次数=(m+1)/2+1;以此类推。可知cnt大于等于1时,当前前缀数列为非k数列。否则为k数列,直接将这k个去掉,ans、cnt初始化。
解题步骤如下:
1)初始化ans=数列第一个值,cnt=1
2)当下一个数等于ans时,cnt++;
当下一个数不等于ans时,cnt–;
当cnt = 0时,说明 当前的 ans 在前k个数中出现次数不过半,即可不考虑这k个数。将ans 赋值为下一个新数,cnt赋值为1,重复2)。

整个数列遍历结束后,cnt一定是大于等于1的,此时的ans就是答案。

import java.util.Scanner;

class Main{
    
    
	public static void main(String args[]) {
    
    
		Scanner sc= new Scanner(System.in);
		while(sc.hasNext()) {
    
    
			int N=sc.nextInt();
			int ans=sc.nextInt();
			int cnt=1;
			for(int i=1;i<N;i++) {
    
    
				int c=sc.nextInt();
				if(ans==c) {
    
    
					cnt++;
				}else {
    
    
					if(cnt==0) {
    
    
						ans=c;
						cnt++;
					}else {
    
    
						cnt--;
					}
				}
			}
			System.out.println(ans);
		}
		
		
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42021845/article/details/118446985
今日推荐