153 题目:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
Find the minimum element.
You may assume no duplicate exists in the array.
Example 1:
Input: [3,4,5,1,2]
Output: 1
Example 2:
Input: [4,5,6,7,0,1,2]
Output: 0
一年半前写过类似的(https://blog.csdn.net/qq_37333947/article/details/88833865)但是现在回看感觉还是好难,二分的边界条件太头疼了。
首先还是看怎么二分,其实画完图就挺直观的了。那么怎么判断我们找到了呢,如果不想用隐式条件(也就是通过low high指针来在最后return),那么我们也可以直接通过mid来判断:如果mid比mid - 1要小,那mid就是turning point就是最小了;而如果mid比mid + 1要大,那么mid + 1就是turning point就是最小。只要这个turning point存在,那我们就可以通过这个turning point来结束这个二分,而如果整个数组是有序的话就不会截止,所以最后需要return nums[0]。
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array.
Memory Usage: 38.3 MB, less than 97.35% of Java online submissions for Find Minimum in Rotated Sorted Array.
class Solution {
public int findMin(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int low = 0;
int high = nums.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (mid > 0 && nums[mid] < nums[mid - 1]) {
return nums[mid];
}
if (mid < nums.length - 1 && nums[mid] > nums[mid + 1]) {
return nums[mid + 1];
}
if (nums[mid] < nums[low]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return nums[0];
}
}
另外也是看了https://leetcode.wang/leetcode-153-Find-Minimum-in-Rotated-Sorted-Array.html才发现,如果mid和low做比较的话,就不能涵盖整体有序的情况,只有和high比才可以,如图左大半边所示。但是因为我这种写法的判断条件是找turning point,不管和high还是low比我都截止不了,所以其实用high用low都差不多。
154题目:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
Find the minimum element.
The array may contain duplicates.
Example 1:
Input: [1,3,5]
Output: 1
Example 2:
Input: [2,2,2,0,1]
Output: 0
Note:
- This is a follow up problem to Find Minimum in Rotated Sorted Array.
- Would allow duplicates affect the run-time complexity? How and why?
如果采用153的上面那种解法,在二分里面找turning point return的话,因为上一题最后return的时候直接无脑return nums[0],但这一题就不太行了,所以最好还是把它拎出来写在最前面(就是我153第一版提交的代码)。因为当有重复元素的时候,min既可能出现在左边,又可能出现在右边,所以其实是无法分成两半的,只能退化成顺序查找。也就是说,153的代码如果最后没在二分while里结束,那就要开始顺序查找了。试过把mid和low的比较如果相等的话high--但还是有点问题,为了简单方便,我就直接在最后加了个for loop。
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array II.
Memory Usage: 38.7 MB, less than 97.93% of Java online submissions for Find Minimum in Rotated Sorted Array II.
class Solution {
public int findMin(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int low = 0;
int high = nums.length - 1;
if (nums[low] < nums[high]) {
return nums[low];
}
while (low <= high) {
int mid = low + (high - low) / 2;
if (mid > 0 && nums[mid] < nums[mid - 1]) {
return nums[mid];
}
if (mid < nums.length - 1 && nums[mid] > nums[mid + 1]) {
return nums[mid + 1];
}
if (nums[mid] < nums[low]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
int min = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
return nums[i];
}
}
return min;
}
}
下面是那个写起来很简洁但是最后是按指针返回的稍微有点理解难度的方法。前面讨论过了如果跟high进行比较就可以不用单独考虑有序的情况,这个在这儿是必须的。我们在移动指针的时候,如果mid < high,我们应该往前面找,但是从图中我们可以看出,这个mid它自身可能就是最小值,所以换边的时候需要考虑到这一点,当要往前找的时候要把mid也同样保留下来,即high = mid(而不是上面一种解法中的mid - 1)。而如果往后找的话就无所谓了,low = mid + 1即可,因此while循环里也要写<而不是<=。如果没有重复元素就直接这样就好了,但如果有重复元素,也就是mid == high的话,就要一步步挪high。但是这样的话最后出来的结果虽然是对的,但index不对(具体没有仔细研究),但可以通过判断high和high - 1的大小来找到turning point,就多加一个if。最后最难的问题就在于,turning point在哪儿。因为while循环的截止条件是low < high,所以停下来的时候一定low >= high,然后就不会分析了……还是不知道为啥是return low啊QAQ 算了,以后再说吧。
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array II.
Memory Usage: 40.2 MB, less than 21.65% of Java online submissions for Find Minimum in Rotated Sorted Array II.
class Solution {
public int findMin(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int low = 0;
int high = nums.length - 1;
while (low < high) {
int mid = low + (high - low) / 2;
if (nums[mid] < nums[high]) {
high = mid;
} else if (nums[mid] > nums[high]) {
low = mid + 1;
} else {
if (nums[high - 1] > nums[high]) {
low = high;
break;
}
high--;
}
}
return nums[low];
}
}