题解:寻找旋转排序数组中的最小值(二分算法)
1.题目
题目链接:LINK
2.暴力求解
思路:挨个便利,看哪里突然变小了就返回该数值即可。当然,如果没有变小的情况可以返回nums[0]位置。
class Solution { public: //暴力求解思路 int findMin(vector<int>& nums) { int fornum = nums[0]; for(size_t i = 1; i < nums.size(); i++) { if(nums[i] < fornum) return nums[i]; fornum = nums[i]; } return nums[0]; } };
3.二分算法
其实这个题目有鲜明的二段性
这里我们以D点作为分界值来区分:
参考代码如下:
class Solution { public: //二分算法 int findMin(vector<int>& nums) { int left = 0, right = nums.size() - 1; int D = nums.size() - 1; while(left < right) { int mid = left + (right - left) / 2; if(nums[mid] <= nums[D]) right = mid; else left = mid + 1; } return nums[left]; } };
当然,这个题我们也可以用nums[0]来作为参考点区分两段数组。
如果mid >= A , left = mid;
如果mid < A , right = mid - 1;
特殊情况:
然后就可以写出这样的代码:
class Solution { public: //二分算法 int findMin(vector<int>& nums) { int left = 0, right = nums.size() - 1; while(left < right) { int mid = left + (right - left) / 2; if(nums[mid] < nums[0]) right = mid; else left = mid + 1; } //特殊情况做处理 // if(nums.size() >=2 && nums[left-1] < nums[left]) return nums[0]; return nums[left]; } };
但是有个问题:就是上面数组,可能会出现这种情况:
也就是我们代码需要找的C点直接没有了,不存在了。实际上这种情况下答案要转换为我们对应的A点,但是你的代码是要的B点。
因此我们可以加上一条特殊判断就行:
class Solution { public: //二分算法 int findMin(vector<int>& nums) { int left = 0, right = nums.size() - 1; while(left < right) { int mid = left + (right - left) / 2; if(nums[mid] < nums[0]) right = mid; else left = mid + 1; } //特殊情况做处理 if(nums.size() >=2 && nums[left-1] < nums[left]) return nums[0]; return nums[left]; } };
4.思考:为什么用A作为界点和用D作为界点不一样,一个需要特殊处理,另一个则不需要???
我们不妨就拿着那个报错的特殊用例来看,假设用A作分界点(用数组第一个值作为划分依据)和用D(用数组最后一个数字作为划分依据)作为分界点的方法都对下面这组数据进行求值:
我们发现两种方法有着不同的划分方式:
说白了,用数组第一个值作为划分依据的方法直接把我们要求的值划没了,但是另一种划分方法巧妙的把这种特殊情况归类到了我们的求值范围内。
换言之,用A作为界点只适用于下图两条线都存在的情况(如果不做特殊处理)
而用D点作为划分依据则适用于所有情况:
5.总结
这个题倒是不难,但是到底用哪个值作为界点值得我们思考。
EOF