📝前言说明:
- 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
- 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
- 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽
视频
- 69. x 的平方根
- 个人解
- 35. 搜索插入位置
- 个人解
- 852. 山脉数组的峰顶索引
- 个人解
- 162. 寻找峰值
- 个人解
- 153. 寻找旋转排序数组中的最小值
- 个人解
- 优质解
- LCR 173. 点名
- 个人解
69. x 的平方根
个人解
思路:
- 确定答案区间:
[0, min(x, 46341)]
(46341 是 2^31 - 1 的平方根 + 1) - 问题转换成:找平方 <= x 的右端点(因为题目向下取整)
mid
选取判断:因为向下取整,left = mid
会死循环
用时:
屎山代码:
class Solution {
public:int mySqrt(int x) {int left = 0, right = min(x, 46341);while(left < right) {unsigned int mid = left + (right - left + 1) / 2;if(mid * mid <= x)left = mid;elseright = mid - 1;}return left;}
};
时间复杂度:O(n)
空间复杂度:O(1)
35. 搜索插入位置
个人解
思路:
- 题目意思:有
target
就返回target
,没有就返回>target
的第一个位置 - 总结一下:就是返回
>= target
的第一个位置 - 细节处理:模拟三种情况:1,正常找到
target
或者正常在数组中间插入;2,全部值都小于target
;3,全部值都大于target
(在这道题中要特殊处理全小于target
的情况)
用时:5:00
屎山代码:
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;elseright = mid;}// 特殊处理全小于target的情况if(nums[right] >= target)return right;elsereturn nums.size();}
};
时间复杂度:O(logN)
空间复杂度:O(1)
852. 山脉数组的峰顶索引
个人解
思路:
- 二段性:每次和右边的数比较
- 右边的数不存在 / 右边的数 <= 当前数:山峰肯定在
[left, mid]
- 右边的数 > 当前数:山峰肯定在
[mid + 1, right]
用时:5:00
屎山代码:
class Solution {
public:int peakIndexInMountainArray(vector<int>& arr) {int left = 0, right = arr.size() - 1;while(left < right){int mid = left + (right - left) / 2;if(mid + 1 == arr.size() || arr[mid + 1] <= arr[mid])right = mid;elseleft = mid + 1;}return right;}
};
时间复杂度:O(logN)
空间复杂度:O(1)
162. 寻找峰值
个人解
思路:
- 这道题的提示3:
nums[i] != nums[i + 1]
,太重要了(保证了一定有一个峰值) - 每次和右侧数字比较
> 右侧的数字
:峰值一定在[left ,mid]
(mid
有可能是峰值)< 右侧的数字
:峰值一定在[mid + 1, right]
用时:10:00(一开始没看到提示3)
屎山代码:
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;elseleft = mid + 1;}return right;}
};
时间复杂度:O(logN)
空间复杂度:O(1)
153. 寻找旋转排序数组中的最小值
个人解
思路:
- 利用数组的有序性二分,找最小
- 但是问题在于:这里在翻转以后可能出现两段数组!一段数组上查找的时候,要判断最小值会不会出行在另一段数组上
- 如何判断呢?如果真的有两段数组,则第二段数组的最大值一定是
nums[n-1]
,如果当前nums[mid] < nums[n - 1]
代表在正确的数组上查找了,反之就是在错误的数组上查找了,要让left
移动到右边
用时:15:00
屎山代码:
class Solution {
public:int findMin(vector<int>& nums) {int n = nums.size();int left = 0, right = n - 1;while(left < right){int mid = left + (right - left) / 2;if(mid + 1 == n || (nums[mid] < nums[mid + 1] && nums[mid] < nums[n - 1]))right = mid;elseleft = mid + 1;}return nums[right];}
};
时间复杂度:O(log n)
空间复杂度:O(1)
优质解
看了官方题解以后想到的:
- 如果翻转了,产生了两个数组,则最小值,一定在第二个数组上!!!
- 并且,前一个数组的元素都大于第二个数组的元素
- 那我们的比较基准就可以和最后一个值进行比较
> nums[n-1]
:数组错了,答案一定在[mid + 1, right]
< nums[n-1]
:答案一定在[left, mid]
,mid
也有可能是答案
代码:
class Solution {
public:int findMin(vector<int>& nums) {int n = nums.size();int left = 0, right = n - 1;while(left < right){int mid = left + (right - left) / 2;if(nums[mid] < nums[n - 1])right = mid;elseleft = mid + 1;}return nums[right];}
};
LCR 173. 点名
个人解
思路:
- 因为数组是升序排序的,且学号从0开始,利用学号和下标对应的特点,找出缺失值在哪一遍
- mid == records[mid] ,则缺失值在 [mid + 1, right]
- mid > records[left, mid]
- 特殊判断,最后一个同学缺席
用时:7:00
屎山代码:
class Solution {
public:int takeAttendance(vector<int>& records) {int n = records.size();if(records[n - 1] == n - 1)return n;int left = 0, right = n - 1;while(left < right){int mid = left + (right - left) / 2;if(mid == records[mid])left = mid + 1;elseright = mid;}return records[right] - 1;}
};
时间复杂度:O(log n)
空间复杂度:O(1)
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!