1095. 山脉数组中查找目标值(二分查找)

题目:1095. 山脉数组中查找目标值

public class FindMountainArray_1095 {

	public static void main(String[] args) {

//		int[] array = { 1, 3, 5, 4, 3, 2, 1 };
//		int[] array = { 1, 2, 3, 4, 5, 3, 1 };
		int[] array = { 0, 1, 2, 4, 2, 1 };
		int target = 3;
		MountainArray mountainArray = new MountainArrayImpl(array);

		System.out.println(findInMountainArray(target, mountainArray));
	}

	public static int findInMountainArray(int target, MountainArray mountainArray) {

		int len = mountainArray.length();

		// 1.用二分法找到mountaninTop山顶下标
		int top = findMountainTop(mountainArray, 0, len - 1);

		// 2.然后对左边升序数组二分查找target目标下标
		int res = findAscArray(mountainArray, 0, top, target);
		// 找到target直接返回
		if (res != -1) {
			return res;
		}

		// 3.对右边降序数组二分查找target目标下标
		return findDecArray(mountainArray, top + 1, len - 1, target);
	}

	/**
	 * 二分法查找最大元素
	 * @param mountainArr 山峰数组
	 * @param left 数组最小下标
	 * @param right 数组最大下标
	 * @return 最大元素下标
	 */
	public static int findMountainTop(MountainArray mountainArr, int left, int right) {

		while (left < right) {
			// 取左中位数
			int mid = left + (right - left) / 2;

			// 左中位数和后面一位比较,确定下一次查找范围
			if (mountainArr.get(mid) < mountainArr.get(mid + 1)) {
				// 山顶在右边,去右边查找
				left = mid + 1;
			} else {
				// 去左边查找,需要包含mid,因为mid可能是最大值
				right = mid;
			}
		}

		// 最后left=right
		return left;
	}

	/**
	 * 二分法查找升序数组中的目标值
	 * @param mountainArr 山峰数组
	 * @param left 数组最小下标
	 * @param right 数组最大下标
	 * @param target 目标值
	 * @return 目标值下标
	 */
	public static int findAscArray(MountainArray mountainArr, int left, int right, int target) {

		while (left < right) {
			// 取左中位数
			int mid = left + (right - left) / 2;

			// 左中位数和后面一位比较,确定下一次查找范围
			if (mountainArr.get(mid) < target) {
				// 山顶在右边,去右边查找
				left = mid + 1;
			} else {
				// 去左边查找,需要包含mid,因为mid可能是最大值
				right = mid;
			}
		}

		// 最后left=right
		// 因为不确定区间缩为一个之后,是否找到target,所以需要判断
		if (mountainArr.get(left) == target) {
			return left;
		}

		return -1;
	}

	/**
	 * 二分法查找降序数组中的目标值
	 * @param mountainArr 山峰数组
	 * @param left 数组最小下标
	 * @param right 数组最大下标
	 * @param target 目标值
	 * @return 目标值下标
	 */
	public static int findDecArray(MountainArray mountainArr, int left, int right, int target) {

		while (left < right) {
			// 取左中位数
			int mid = left + (right - left) / 2;

			// 左中位数和后面一位比较,确定下一次查找范围
			if (mountainArr.get(mid) > target) {
				// 去右边查找
				left = mid + 1;
			} else {
				// 去左边查找,需要包含mid,因为mid可能是最大值
				right = mid;
			}
		}

		// 最后left=right
		// 因为不确定区间缩为一个之后,是否找到target,所以需要判断
		if (mountainArr.get(left) == target) {
			return left;
		}

		return -1;
	}
}

class MountainArrayImpl implements MountainArray {
	private int[] array;
	private int length;

	public MountainArrayImpl(int[] array) {
		this.array = array;
		this.length = array.length;
	}

	@Override
	public int get(int index) {
		return this.array[index];
	}

	@Override
	public int length() {
		return this.length;
	}
}

interface MountainArray {
	public int get(int index);

	public int length();
}

posted @ 2020-05-13 11:12  ageovb  阅读(51)  评论(0编辑  收藏  举报