剑指Offer39:数组中出现次数超过一半的数字

题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在这个数组中出现了5次,超过数组 长度的一半,因此输出2

分析:
若一个数组中有一个数字出现了数组长度的一半以上,则必是这个数组的中位数

方法一:最简单粗暴,将数组排序,找出中位数, 时间复杂度为O(nlog(n))

	public int Method1(int[] nums) {
		Arrays.sort(nums);
		return nums[nums.length/2];
	}

方法二:
基于Partition函数
* 随机选择一个数,比它小的都在这个数的左边,比它大的都在这个数的右边。
* 若这个数在排完之后的次序正好为n/2,那就是这个数,若不是。则在n/2的左边或者右边查找

	public int Method2(int[] nums) {
		int index = Partition(nums, 0, nums.length - 1);
		int start = 0;
		int end = nums.length - 1;
		while(index != nums.length /2) {
			if(index < nums.length /2) {
				start = index + 1;
				index = Partition(nums, start, end);
			}else {
				end = index - 1;
				index = Partition(nums, start, end);
			}
		}
		return nums[index];
	}
	
	private int Partition(int[] nums, int start, int end) {
		if(start<0 || end >= nums.length) {
			return -1;
		}
		
		int small = start - 1; //作用是用来记录比末尾值还要小的值应该在的位置
		for(int i = start; i <= end; i++) {
			if(nums[i] < nums[end]) {
				small++;
				if(small != i) {
					int temp = nums[small];
					nums[small] = nums[i];
					nums[i] = temp;
				}
			}
		}
		
		/*
		 * 把末尾值放在他应该在的地方去
		 */
		small++;
		int temp = nums[end];
		nums[end] = nums[small];
		nums[small] = temp;
		
		return small;
	}

方法三:
采取一种类似投票的思路:由于存在一个数超过一半次数
因此,从0位次开始,第一个数字出现,记录该数字,并记录该数字出现的次数。
若下一个数字和上一个数字不一样,times–。且上一个数字的出现次数为0次了。则换数字

public int Method3(int[] nums) {
		int times = 1;
		int result = nums[0];
		for(int i = 1; i < nums.length; i++) {
			if(times == 0) {
				result = nums[i];
				times = 1;
			}else {
				if(nums[i] != result) {
					times--;
				}else {
					times++;
				}
			}
		}
		return result;
	}

猜你喜欢

转载自blog.csdn.net/caoyiqi885/article/details/84027451