赞
踩
二分查找:当看到题目中出现有序数组、无重复元素时,可以考虑用二分查找方法。
思路:如果数组中间值大于查找值,则往数组的左边继续查找,令 right = mid - 1,如果小于查找值则往右边继续查找,令 left = mid + 1 。
一、 LeetCode题 704.二分查找 704. 二分查找 - 力扣(LeetCode)
题目描述:
代码:
class Solution { public: int search(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while (left <= right){ int mid = (right - left) / 2 + left; // 防止溢出 等同于(left + right)/2 if (nums[mid] < target) left = mid + 1; else if(nums[mid] > target) right = mid - 1; else return mid; //与target相等时返回索引 } return -1; } };注意:
(1) right = 数组长度 - 1 对应循环终止条件为 left <= right
(2) 在循环内分了三种情况,当数组内某一元素与target值相等时,返回索引,不能在此处保存索引,在循环外return索引,此时会卡死在循环中。如定义另一变量ans保存索引。
else ans = mid;
二、LeetCode题 69.x的平方根 69. Sqrt(x) - 力扣(LeetCode)
题目描述:与上一道题目不同的是,结果只保留整数部分,利用二分查找法不一定找到一个整数的平方与目标值相等,只需要找到 mid*mid <= x 中的最大 mid 值,循环内条件需要改变。
代码:
class Solution { public: int mySqrt(int x) { int left = 0; int right = x; int ans = 0; while(left <= right){ int mid = (right - left)/2 + left; if((long long)mid * mid <= x){ ans = mid; left = mid + 1; } else{ right = mid - 1; } } return ans; } };与之类似的题目有 367.有效的完全平方数 367. 有效的完全平方数 - 力扣(LeetCode)
在上一道题 x的平方根 的基础上直接更改,只需要加入判断条件:
if(ans*ans == num) return true; else return false;或者直接沿用第一道题的思路。
三、LeetCode题 34. 在排序数组中查找元素的第一个和最后一个位置
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
题目描述:虽然这道题中有重复元素,但仍可以用二分查找法解决。
思路1:利用二分查找法在 nums 中找到 target 的索引,再左右遍历探索,找到 target 的第一个位置和最后一个位置。
代码:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { if(nums.size()==1 && target==nums[0]) return{0,0}; int left = 0, right = nums.size() - 1; int ans = -2; while (left <= right) { int mid = (right - left) / 2 + left; if (nums[mid] > target) right = mid - 1; else if(nums[mid] < target) left = mid + 1; else {ans = mid;break;} } if(ans==-2) return{-1,-1}; int ans1=ans, ans2= ans; while(ans1>0 && nums[ans1-1]==nums[ans1]) ans1--; while(ans2<(nums.size()-1) && nums[ans2+1]==nums[ans2]) ans2++; return {ans1,ans2}; } };思路2:利用两次二分查找法,分别查找第一个大于等于 target 的下标(右边界)和 第一个大于 target的下标(左边界)。
代码:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int leftBorder = getLeftBorder(nums, target); int rightBorder = getRightBorder(nums, target); if (leftBorder == -2 || rightBorder == -2) return {-1, -1}; if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1}; return {-1, -1}; } private: int getRightBorder(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况 while (left <= right) { int middle = left + ((right - left) / 2); if (nums[middle] > target) { right = middle - 1; } else { // 寻找右边界,nums[middle] == target的时候更新left left = middle + 1; rightBorder = left; } } return rightBorder; } int getLeftBorder(vector<int>& nums, int target) { int left = 0; int right = nums.size() - 1; int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况 while (left <= right) { int middle = left + ((right - left) / 2); if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right right = middle - 1; leftBorder = right; } else { left = middle + 1; } } return leftBorder; } };优化:可将寻找左右边界的函数合在一起。(官方题解)
本文根据代码随想录顺序刷题。代码随想录 (programmercarl.com)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。