剑指offer-面试题38-数字在排序数组中出现的次数

package case38_NumbersOfK;

/**
 * 题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4。
 * 
 * @author WangSai
 *
 */
public class NumbersOfK {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		int[] arr1 = { 1, 2, 5, 16, 16, 20 };
		int num1 = 16;
		System.out.println("1次:" + getMyTimes(arr1, num1));
		int[] arr2 = { 1, 1, 1, 1, 1, 1, 1 };
		int num2 = 1;
		System.out.println("7次:" + getMyTimes(arr2, num2));
		int[] arr3 = { 1 };
		int num3 = 1;
		System.out.println("1次:" + getMyTimes(arr3, num3));
		int[] arr4 = { 2, 2, 2, 2, 2, 2 };
		int num4 = 1;
		System.out.println("0次:" + getMyTimes(arr4, num4));
	}

	/**
	 * 获取num在arr数组中出现的次数
	 * 
	 * @param arr,待查找的数组
	 * @param num,待查找的数字
	 * @return 若数组中不存在该数字,返回-1;若存在则返回出现的次数。
	 */
	private static int getMyTimes(int[] arr, int num) {
		// 异常值检测
		if (arr == null || arr.length <= 0) {
			throw new IllegalArgumentException("非法输入参数,请重新检查...");
		}
		// 二分查找,获取num在arr中的位置
		int index = binarySearch(arr, 0, arr.length - 1, num);
		// 若index-1,说明该数字未出现。
		if (index == -1)
			return 0;
		// 查找最左侧的第一个num,并返回角标
		int firstIndex = getFirstIndexOfNum(arr, index, num);
		// 查找最右侧的最后一个num,并返回角标
		int lastIndex = getLastIndexOfNum(arr, index, num);
		// 返回num在数组中出现的次数
		return lastIndex - firstIndex + 1;
	}

	/**
	 * 获取num最后一次出现时在arr数组中对应的角标
	 * 
	 * @param arr,待查找的数组
	 * @param index,num在arr中的角标
	 * @param num,待查找的数字
	 * @return 数字num最后一次出现时在arr数组中对应的角标
	 */
	private static int getLastIndexOfNum(int[] arr, int index, int num) {
		// 若index为arr[]的最后一个角标,则直接返回index
		if (index == arr.length - 1)
			return index;
		// 若arr[index]不是最后一个元素,并且下一个元素不是num,则直接返回当前的index
		else if (arr[index + 1] != num)
			return index;
		// 在数组后半段继续查找
		int pos = binarySearch(arr, index + 1, arr.length - 1, num);
		return getLastIndexOfNum(arr, pos, num);
	}

	/**
	 * 获取 数组arr中第一次出现num时的角标,时间复杂度O(logn)
	 * 
	 * @param arr,待查找的数组
	 * @param index,num在arr中的角标
	 * @param num,待查找的数字
	 * @return 数组arr中第一次出现num时的角标
	 */
	private static int getFirstIndexOfNum(int[] arr, int index, int num) {
		// 若index为arr[]的0角标,则直接返回index
		if (index == 0)
			return 0;
		// 若arr[index]不是第一个元素,并且前一个元素不是num,则直接返回当前的index
		else if (arr[index - 1] != num) {
			return index;
		}
		// 在前半段继续查找,递归
		int pos = binarySearch(arr, 0, index - 1, num);
		return getFirstIndexOfNum(arr, pos, num);

	}

	/**
	 * 二分查找,时间复杂度O(logn)
	 * 
	 * @param arr,待查找的数组
	 * @param low
	 * @param high
	 * @param num,待查找的数字
	 * @return 查找的数字所在的角标,或者 若不存在则返回-1
	 */
	private static int binarySearch(int[] arr, int low, int high, int num) {
		while (low <= high) {
			int middle = (low + high) / 2;
			if (arr[middle] < num) {
				low = middle + 1;
			} else if (arr[middle] > num) {
				high = middle - 1;
			} else {
				return middle;
			}
		}
		return -1;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值