寻找峰值

102 阅读1分钟

题目

二分查找法

public class Main {
    public static void main(String[] args) {

        Main main = new Main();
        int [] nums = new int[] {1};
        main.findPeakElement(nums);
    }

    public int findPeakElement(int[] nums) {
        if (nums.length == 1) {
            return 0;
        }

        // 一个无序数组存在多个峰值 得到任何一个即可, 并且相邻元素不相等
        // 峰值只可能存在于三个位置 边界+峰值+下降序列 上升序列+峰值+下降序列 上升序列+峰值+下降序列
        // 因此题目可以转变成寻找上升和下降序列, 来缩小峰值可能存在的范围, 提高查找效率

        // 利用二分法
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (mid - 1 < 0) {
                // 左边是边界
                if (nums[mid] > nums[mid + 1]) {
                    return mid;
                } else {
                    left = mid + 1;
                }
            } else if (mid + 1 == nums.length) {
                // 右边是边界
                if (nums[mid] > nums[mid - 1]) {
                    return mid;
                } else {
                    right = mid - 1;
                }
            } else {
                if (nums[mid] < nums[mid - 1]) {
                    // mid位于下降序列 峰值在mid左侧
                    right = mid - 1;
                } else if (nums[mid] < nums[mid + 1]) {
                    // mid位于上升序列 峰值在mid右侧
                    left = mid + 1;
                } else {
                    return mid;
                }
            }

        }
        return mid;
    }

}

基本思路

  1. 一看到题目能想到的就是遍历数组, 然后比较nums[i - 1], nums[i], nums[i + 1]三个值的大小关系, 判断是否是峰值, 但是显然这个方法太蠢了

  2. 扩展来想, 题目中的峰值不只一个, 同时峰值只可能存在于三个位置 边界+峰值+下降序列 上升序列+峰值+下降序列 上升序列+峰值+下降序列, 因此可以通过二分法缩小查找范围, 保证范围内一定存在一个峰值即可