1. 程式人生 > >劍指Offer39:陣列中出現次數超過一半的數字

劍指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;
	}