LeetCode 153, 154

175 阅读1分钟

最近在给我带的实习生帮忙,然后周末又闷着头刷了几天hard,然后又开始学系统设计,因此好几天没写题解了。不过以后还是会写。

LeetCode 153 Find Minimum in Rotated Sorted Array

链接:leetcode.com/problems/fi…

方法1:二分(普通写法)

时间复杂度:O(logn)

空间复杂度:O(1)

想法:就是普通的二分题目,大概来说在LeetCode的二分题里算比较简单的。首先看数组第一个元素和最后一个元素,排除数组完全没有rotate或者rotate了半天又回来了的情况。这道题每次算一个mid分成两半,如果说nums[mid]与nums[left]比较,然后nums[mid]比较大,那就说明从mid到left是一路递增的,那么就舍掉这一半。

代码:

class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        
        if (nums[0] < nums[n - 1]) {
            return nums[0];
        }
        
        int left = 0, right = n - 1;
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[left]) {
                left = mid;
            }
            else {
                right = mid;
            }
        }
        
        return Math.min(nums[left], nums[right]);
    }
}

方法2:二分(递归)

时间复杂度:O(logn)

空间复杂度:O(logn),栈空间

想法:这是我第一次见到递归形式的二分,从花花酱那里学来的,链接是www.youtube.com/watch?v=P4r… 。首先单论递归的话代码其实也比较好理解,但有一个问题在于这样写为什么是O(logn)的算法,其实这题不是T(n) = O(1) + 2 * T(n / 2),而是T(n) = O(1) + T(n / 2),然后分出来的两块一定有一块是sorted的,因此求解的时候会马上返回。

代码:

class Solution {
    public int findMin(int[] nums) {
        return findMin(nums, 0, nums.length - 1);
    }
    
    private int findMin(int[] nums, int l, int r) {
        if (l + 1 >= r) {
            return Math.min(nums[l], nums[r]);
        }
        
        if (nums[l] < nums[r]) {
            return nums[l];
        }
        
        int mid = l + (r - l) / 2;
        return Math.min(findMin(nums, l, mid - 1), findMin(nums, mid, r));
    }
}

LeetCode 154 Find Minimum in Rotated Sorted Array II

链接:leetcode.com/problems/fi…

方法:二分(其实是分治)

时间复杂度:O(n)

空间复杂度:O(logn),栈空间

想法:这个题与上一题唯一的不同在于数组里面的元素不再unique,会出现重复元素,然后根据上面的题的分析,我们二分之所以可以进行,就是因为分出mid来之后,我们可以根据nums[mid]和nums[left]的关系(普通写法),或者l和r的关系(递归写法),去舍弃一段。但因为现在有重复元素,就没有办法知道应该舍弃哪边去哪边,因此得两边都去。导致时间复杂度变成T(n) = O(1) + 2 * T(n / 2),也就是O(n)。但是代码跟上面的递归写法代码完全一致。

代码:

class Solution {
    public int findMin(int[] nums) {
        return findMin(nums, 0, nums.length - 1);
    }
    
    private int findMin(int[] nums, int l, int r) {
        if (l + 1 >= r) {
            return Math.min(nums[l], nums[r]);
        }
        
        if (nums[l] < nums[r]) {
            return nums[l];
        }
        
        int mid = l + (r - l) / 2;
        
        return Math.min(findMin(nums, l, mid - 1), findMin(nums, mid, r));
    }
}