超过一半的数字

题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

思路:解法一、排序完后返回arr[N/2] O(nlgn) Arrays.sort(arr); System.out.println(arr[N/2]);
    解法二、hash统计
    解法三、顺序统计,就跟寻找乱序数组中第K大的数解法一样。O(N),那么这里就是求乱序数组中第N/2大的数,限制:需要改动数组的内容
    解法四、不同的数,进行消除

代码:

public class MoreThanHalf {

	public static void main(String[] args) {
		
		f(new int[]{5,6,6,6,2,3,6});

	}
	
	// 不同的数,进行消除,O(N)
	public static void f(int arr[]){
		//候选数  先定位第一个元素
		int candidate = arr[0];
		// 出现的次数
		int nTimes = 1;
		// 扫描数组
		for (int i = 1; i < arr.length; i++) {
			// 两两消减为0,应该把现在的元素作为候选值
			if (nTimes==0 ) {
				candidate = arr[i];
				nTimes = 1;
				continue;
			}
			// 如果遇到和候选值相同的,次数加一
			if (arr[i]==candidate) {
				nTimes++;
				// 不同的数,进行消减
			}else {
				nTimes--;
			}
		}
		//System.out.println(nTimes);
		if (nTimes==0) {
			System.out.println(-1);
		}else {
			System.out.println(candidate);
		}
		
	}

}

结果:

  

趣味拓展:加强版水王问题,假如出现的次数恰好为个数的一般,求出这个数。

思路:有个巧妙的方法扫描一遍数组就解决问题,水王发的贴子占总数的一半,说明总数为偶数;不失一般性,假设隔一个数就是水王的id,两两不同最后一定会消减为0,如果水王是最后一个元素,那么每次扫描的时候,多一个动作,和最后一个元素做比较,单独计数,计数恰好一半。如果不是,那么去掉最后一个元素,水王就是留下的那么candidate。

代码:

public class MoreThanHalf {

	public static void main(String[] args) {
		//进行测试数据要满足测试条件 不然结果会错误
		f(new int[]{6,6,6,5,6,1,2,3,4,6});

	}
	
	// 不同的数,进行消除,O(N)
	public static void f(int arr[]){
		//候选数  先定位第一个元素
		int candidate = arr[0];
		// 出现的次数
		int nTimes = 1;
		int countOfLast = 1;  // 统计这个元素出现的次数
		// 扫描数组
		for (int i = 1; i < arr.length; i++) {
			if (arr[i-1]==arr[arr.length-1]) {
				countOfLast++;
			}
			// 两两消减为0,应该把现在的元素作为候选值
			if (nTimes==0 ) {
				candidate = arr[i];
				nTimes = 1;
				continue;
			}
			// 如果遇到和候选值相同的,次数加一
			if (arr[i]==candidate) {
				nTimes++;
				// 不同的数,进行消减
			}else {
				nTimes--;
			}
		}
		//System.out.println(nTimes);
		if (countOfLast==arr.length/2) {
			System.out.println(arr[arr.length-1]);
		}else {
			System.out.println(candidate);
		}
		
	}

}

结果:

  

原文地址:https://www.cnblogs.com/xiaoyh/p/10273429.html