1.二分查找
704. 二分查找 - 力扣(LeetCode)
二分查找算法要确定“二段性”,时间复杂度为O(lonN)。为了防止数据溢出,以是求mid时要用防溢出的方式。
- class Solution {
- public:
- int search(vector<int>& nums, int target)
- {
- int left = 0, right = nums.size() - 1;
- while(left <= right)
- {
- //int mid = (left + right) / 2;
- int mid = left + (right - left) / 2;//防溢出
- if(target > nums[mid])
- {
- left = mid + 1;
- }
- else if(target < nums[mid])
- {
- right = mid - 1;
- }
- else
- {
- return mid;
- }
- }
- return -1;
- }
- };
复制代码 淳厚二分模版
- while(left <= right)
- {
- int mid = left + (right - left) / 2;//防溢出
- if(......)
- {
- left = mid + 1;
- }
- else if(......)
- {
- right = mid - 1;
- }
- else
- {
- return ......;
- }
- }
复制代码 2.在排序数组中查找元素的第一个和末了一个位置
34. 在排序数组中查找元素的第一个和末了一个位置 - 力扣(LeetCode)
用二分查找解决,要查找一个区间要找去左端点和右端点。
1. 查找区间的左端点
细节处理:
1. 循环条件 left < right 而不是left <= right ,因为left == right 的时候就是最终效果,无需判定。假如判定了就会死循环(当left和right构成的区间中存在效果,并且 nums[mid] >= t时,此时mid也等于left和right,进行上述操作的时候会导致right = mid一直在原地,以是导致死循环)。
2. 求中点的操作
left + (right - left)/ 2 要向下取整,当剩两个点让mid的指针指向left。
2.查找区间右端点
与查找区间左端点的方法雷同,只是处理条件差异。
1.当nums[mid] <= target 时left == mid。
2.当nums[mid] > target 时right == mid - 1。
循环条件:left < right 和上述原因一致。
求中点的方式 left + (right - left + 1) / 2 要向上取整,当剩两个点让mid的指针指向right。
- class Solution {
- public:
- vector<int> searchRange(vector<int>& nums, int target)
- {
- if(nums.size() == 0)
- return {-1, -1};
- int left = 0, right = nums.size() - 1;
- int begin = 0;
- while(left < right)//确定区间的左端点
- {
- int mid = left + (right - left) / 2;//防溢出写法
- if(nums[mid] < target)
- left = mid + 1;
- else
- right = mid;
-
- }
- //判断是否有结果
- if(nums[left] != target)
- return {-1,-1};
- else
- begin = left;
- left = 0, right = nums.size() - 1;
- while(left < right)//确定区间的右端点
- {
- int mid = left + (right - left + 1) / 2;
- if(nums[mid] <= target)
- left = mid;
- else
- right = mid - 1;
- }
- //如果存在左端点,那么右端点也一定存在,所以不用判断了,直接返回
- return {begin, right};
-
- }
- };
复制代码 总结二分模版
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(......)
- left = mid + 1;
- else
- right = mid;
-
- }
- while(left < right)//确定区间的右端点
- {
- int mid = left + (right - left + 1) / 2;
- if(......)
- left = mid;
- else
- right = mid - 1;
- }
复制代码 3. 搜索插入位置
35. 搜索插入位置 - 力扣(LeetCode)
思路:二分查找,用左端点的模版,直接找到查找加返回要插入位置的值。假如未找到target,则检查target是否大于nums[right]:假如是,插入位置为right + 1;否则,插入位置为right(即第一个大于等于target的位置)。
- class Solution {
- public:
- int searchInsert(vector<int>& nums, int target)
- {
- int left = 0, right = nums.size() - 1;
-
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] < target)
- left = mid + 1;
- else
- right = mid;
- }
- if(target > nums[right])
- return right + 1;
- else
- return right;
- }
- };
复制代码 4. x的平方根
69. x 的平方根 - 力扣(LeetCode)
直接将1 ~ x作为查找区间,找小于等于mid*mid的x的值
- class Solution {
- public:
- int mySqrt(int x)
- {
- if(x < 1)
- return 0;
- long long left = 0, right = x;
- while(left < right)
- {
- long long mid = left + (right - left + 1) / 2;
- if(mid * mid <= x)
- left = mid;
- else
- right = mid - 1;
- }
- return left;
- }
- };
复制代码 5. 山脉数组的峰顶索引
852. 山脉数组的峰顶索引 - 力扣(LeetCode)
运用二分查找算法,因为在山脉数组中,在前一段山脉arr[mid] > arr[mid - 1],在后一段山脉arr[mid] < arr[mid - 1];根据这个二段性,使用二分查找。
- class Solution {
- public:
- int peakIndexInMountainArray(vector<int>& arr)
- {
- int left = 0, right = arr.size() - 1;
- while(left < right)
- {
- int mid = left + (right - left + 1) / 2;
- if(arr[mid] > arr[mid - 1])
- left = mid;
- else
- right = mid - 1;
- }
- return left;
- }
- };
复制代码
6. 探求峰值
162. 探求峰值 - 力扣(LeetCode)

运用二分查找算法:对于区间中nums 和 nums[i + 1],假如nums < nums[i + 1],那么这段区间程上升趋势,因为nums[-1]和nums[n] =  ,以是在后一段区间内一定有峰值,让left = mid + 1.
假如nums > nums[i + 1],程下降趋势,在前一段区间内一定有峰值,让right = mid。
- class Solution {
- public:
- int findPeakElement(vector<int>& nums)
- {
- int left = 0, right = nums.size() - 1;
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] > nums[mid + 1])
- right = mid;
- else
- left = mid + 1;
- }
- return left;
- }
- };
复制代码
7.探求旋转排序数组中的最小值
153. 探求旋转排序数组中的最小值 - 力扣(LeetCode)
思路:使用二分查找,因为这个数组是有二段性的(要找的值为第二段的第一个元素),将这个数组分为两段第一段的值一定比第二段的值大,以是根据nums[mid]和nums[n - 1]的关系作为比力。nums[mid]>nums[n - 1],阐明在mid第一段,以是要让left = mid + 1;nums[mid] <= nums[n - 1]时,阐明mid在第二段上,要让right = mid。
第二种方法是一nums[0]作为比力值,只是这种有特殊环境,满是升序的时候会导致mid一直向后走,以是找特殊判定一下升序的环境。
- class Solution {
- public:
- int findMin(vector<int>& nums)
- {
- /*int left = 0, right = nums.size() - 1, n = nums.size();
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] > nums[n - 1])
- left = mid + 1;
- else
- right = mid;
- }
- return nums[right];*/
- int left = 0, right = nums.size() - 1, n = nums.size();
- if(nums[n - 1] > nums[0])
- return nums[0];
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(nums[mid] >= nums[0])
- left = mid + 1;
- else
- right = mid;
- }
- return nums[right];
- }
- };
复制代码 8.点名
LCR 173. 点名 - 力扣(LeetCode)
1.哈希表;2.直接遍历找布局;3.位运算;4.求和公式。这些方法的时间复杂度都是O(N)。
方法5:二分查找:这个数组有二段性,分成两段判定对应的值是否相等,还必要处理一下全升序的环境
- class Solution {
- public:
- int takeAttendance(vector<int>& records)
- {
- int left = 0, right = records.size() - 1, n = records.size();
- if(records[n - 1] == n - 1)
- return n;
- while(left < right)
- {
- int mid = left + (right - left) / 2;
- if(records[mid] == mid)
- left = mid + 1;
- else
- right = mid;
- }
- return right;
- }
- };
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|