數字在排序數組中出現的次數


題目描述
統計一個數字在排序數組中出現的次數。

方法一
最簡單的方法就是遍歷整個數組。沒什么好說的,很low.

	/** * 方法一 * @param array * @param k * @return */
	public int GetNumberOfK(int [] array , int k) {
		if(array == null || array.length == 0) {
			return 0;
		}

		int times = 0;
		for (int i = 0; i < array.length; i++) {
			if(array[i] == k) {
				++times;
			}
		}
		
		return times;
	}

方法二
數組是有序的,我們可以利用二分查找。直觀的一個思路就是通過二分查找獲得一個k在數組中的下標,然后順序的在k的前面和后面尋找和k相等的數。

	/** * 方法二 */
	public int GetNumberOfK_2(int [] array , int k) {
		if(array == null || array.length == 0) {
			return 0;
		}
		int low = 0, high = array.length - 1, mid = 0, times = 0;
		while(low <= high) {
			mid = (low + high) / 2;
			if(k < array[mid]) {
				high = mid - 1;
			}
			else if(k > array[mid]) {
				low = mid + 1;
			}
			else {
				times = 1;
				break;
			}
		}
		
		for (low = mid - 1; (low >= 0) && (array[low] == k); low--) {
			times += 1;
		}
		for (low = mid + 1; (low < array.length) && (array[low] == k); low++) {
			times += 1;
		}
		
		return times;
	}

但是很可能面試官還不滿意,還想要更快的方法。

方法三
通過二分查找獲得數組中第一個k的下標和最后一個k的下標,然后下標相減就是出現的次數。思路是通過二分找到一個k,先判斷這個數字是不是第一個k,如果中間數字的前面一個數字不是k,那么此時中間數字剛好就是第一個k,如果中間數字的前面一個數字也是k,那么第一個k肯定在數組的前半段,繼續二分,這是遞歸的過程。
尋找第一個k下標的方法(遞歸):

	private int FetFirstK(int[] elem, int k, int start, int end) {
		if(start > end) {
			return -1;
		}
		
		int mid = (start + end) / 2;
		if(elem[mid] > k) {
			return FetFirstK(elem, k, start, mid - 1);
		}
		else if(elem[mid] < k) {
			return FetFirstK(elem, k, mid + 1, end);
		}
		else if(mid - 1 >= 0 && elem[mid - 1] == k) {
			return FetFirstK(elem, k, start, mid - 1);
		}
		else {
			return mid;
		}
	}

尋找最后一個k的下標的方法(非遞歸):

	private int FetLastK(int[] elem, int k, int start, int end) {
		int mid = (start + end) / 2;
		while(start <= end) {
			if(elem[mid] > k) {
				end = mid - 1;
			}
			else if(elem[mid] < k) {
				start = mid + 1;
			}
			else if(mid + 1 <elem.length && elem[mid + 1] == k) {
				start = mid + 1;
			}
			else {
				return mid;
			}
			
			mid = (start + end) / 2;
		}
		
		return -1;
	}

主方法:

	/** * 方法三 * @param array * @param k * @return */
	public int GetNumberOfK_3(int [] array , int k) {
		if(array == null || array.length == 0) {
			return 0;
		}
		
		int firstK = FetFirstK(array, k, 0, array.length - 1);
		int lastK = FetLastK(array, k, 0, array.length - 1);
		if(firstK != -1 && lastK != -1) {
			return lastK - firstK + 1;
		}
		return 0;

	}

方法四
因為數組中都是整數,所以可以稍微變一下,不是搜索k的兩個位置,而是搜索k-0.5和k+0.5這兩個數應該插入的位置,然后相減即可。

	/** * 方法四 * @param array * @param k * @return */
	public int GetNumberOfK_4(int [] array , int k) {
		if(array == null || array.length == 0) {
			return 0;
		}
		
		return biSearch(array, k + 0.5) - biSearch(array, k - 0.5);
	}
	
	private int biSearch(int[] elem, double num) {
		int start = 0, end = elem.length - 1, mid = (start + end) / 2;
		while(start <= end) {
			if(elem[mid] < num) {
				start = mid + 1;
			}
			else if(elem[mid] > num) {
				end = mid - 1;
			}
			mid = (start + end) / 2;
		}
		return start;
	}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM