最近在给我带的实习生帮忙,然后周末又闷着头刷了几天hard,然后又开始学系统设计,因此好几天没写题解了。不过以后还是会写。
LeetCode 153 Find Minimum in Rotated Sorted Array
方法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
方法:二分(其实是分治)
时间复杂度: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));
}
}