YSMull
<-- algorithm



原题链接

分析

这里只给出可以无脑使用二分模板的方法:
把这个旋转数组去掉最后一个元素(target)后,剩余的部分仍然是一个旋转数组(arr’)
原命题等价为:寻找 arr’ 中第一个小于 target 的元素。

用左闭右开 True/False 模板来做,当没有找到这个元素的时候,left 刚好指向的是 target。

实现

2020.4.14 rust 重做

impl Solution {
    pub fn find_min(nums: Vec<i32>) -> i32 {
        let mut i = 0;
        let mut j = nums.len() - 1;
        while i < j {
            let mid = i + (j - i) / 2;
            if nums[mid] <= nums[nums.len() - 1] {
                j = mid;
            } else {
                i = mid + 1;
            }
        }
        return nums[i];
    }
}

2020.1.23 刚学二分时做的

class Solution {
    static int search(int l, int r, Predicate<Integer> f) {
        while (l < r) {
            int m = l + (r - l) / 2;
            if (f.test(m)) {
                r = m;
            } else {
                l = m + 1;
            }
        }
        return l; // 此时 l 等于 r,并且 f(l) 是第一个等于 true 的点
    }

    static int findMin(int[] array) {
        int l = 0, r = array.length - 1;
        // 第一个小于等于最右端的点的元素位置,即最小值
        int index = search(l, r, m -> array[m] <= array[r]);
        return array[index];
    }
}

我自己的一开始写的分类讨论的版本,看起来还是比较乱的

class Solution {
    public int findMin(int[] nums) {
        int i = 0;
        int j = nums.length - 1;
        // 如果是升序的
        if (nums[i] <= nums[j]) return nums[i];
        while (true) {
            if (i == j || i == j - 1) return nums[j];
            int mid = (i + j) / 2;
            int n = nums[mid], l = nums[i], r = nums[j];
            if (n > l) { // n 在上方
                if (nums[mid+1] > nums[mid]) {
                    i = mid + 1;
                } else {
                    return nums[mid + 1];
                }
            } else { // n 在下方
                if (nums[mid] > nums[mid - 1]) {
                    j = mid - 1;
                } else {
                    return nums[mid];
                }
            }
        }
    }
}