今日任务 :数组理论基础,704. 二分查找,27. 移除元素
碎碎念
在正式打卡之前,想简单介绍一下自己的情况,同时也是记录自己此刻的一种状态吧。本人基础很差,本科毕业于民办三本,二战考研也没有上岸心仪的学校,调剂到了一所双非院校。科研三年做的是医工交叉的方向,和找工作毫无关联。整体的状态属于除了学习的一切,我都感觉我做的还不错,唯独学习,我感觉自己差劲到极点。
一路走来,都属于摆烂状态,可能只有考研期间真正为了自己的努力拼搏过。现在我已经研三,秋招也结束了。整个秋招之路,收获了一家上市公司的嵌软岗位,一家驱动工程师和数不清的高校计算机专任教师offer,但是我都没有签。没有签约的原因并不是说自己觉得自己了不起想要更好的,而是处于种种原因感觉都不适合自己,我也很焦虑。秋招之前抱着雄心壮志说要好好刷力扣,好好搞项目,幻想着找一份不错的C++开发,但是事实总是很残酷,时间过分飞快,我自己也越来越摆烂,别人劝我考公务员,说我适合去高校,说我不适合写代码,说女生去了私企面临结婚生子,也是分分钟会被辞退。一年以前,我会反驳,我会不服气,想要证明自己,但是科研压力、个人惰性、导师的高标准要求,让我只想抽空摆烂,毫无斗志可言,2023年11月找工作两个多月过去,当别人再说我不适合写代码,我会说对,确实,我承认。12月当我真正找到教师工作的时候,我发现我还是不甘心,并不是说教师不好,我也羡慕一年三个月的假期,但是可能我太心气傲了吧,我还是想春招在拼一下。
一直磨磨唧唧没有勇气开始我的春招准备,可能现在也确实晚了,但是我还是想试一下。想证明自己也可以,也想给那些和我一样的,出身不好但也不愿安于现状的朋友们一些鼓励吧。希望我两个月时间努力刷题,看八股,巩固项目,可以有好的收获!不求进什么大厂,只希望能找到c++开发的中厂的工作!!希望抓住校招这宝贵的机会!
704 二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
前言
● 这道题也是我准备秋招刷的第一道题(当时只刷了55道题,没有坚持下去,现在后悔万分)。
● 本题可以暴力直接遍历数组直接查找target,这样的话时间复杂度为O(n)
● 采用二分查找可以提高效率,时间复杂度O(log n),但是要有前提条件,
- 有序数组;
- 数组中最好无重复元素,如果有重复元素要思考怎么解决;
代码
● 这道题我解题花费4分钟,直接出于固有印象以及熟悉写了一下代码,虽然也运行通过了,但看了卡哥的讲解,发现自己没有考虑周全。
- 我直接采用了左右指针左闭右闭,没有考虑边界问题。也可以尝试左闭右开;
- 在判断中间指针时,没有考虑溢出的可能,应该写为
int mid = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
更好;
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;
if(nums[mid]<target){
left = mid+1;
}
else if(nums[mid]>target){
right = mid-1;
}
else{
return mid;
}
}
return -1;
}
};
左闭右开的写法:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size();
while(left<right){
int mid = left + ((right - left) >> 1);
if(nums[mid]<target){
left = mid+1;
}
else if(nums[mid]>target){
right = mid;
}
else{
return mid;
}
}
return -1;
}
};
相关题目练习1:35. 搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;
int mid = 0;
while(left<=right){
mid = (left+right)/2;
if(nums[mid]<target){
left = mid+1;
}
else if(nums[mid]>target){
right = mid-1;
}
else{
return mid;
}
}
return right + 1;
}
};
相关题目练习2:34.在排序数组中查找元素的第一个和最后一个位置(仍需二刷)
这道题要在排序数组中查找,所以第一时间想到了二分查找,但是由于target不止一个,所以之前的传统二分查找不在适用。对于返回下标不为1个的情况下,具体怎么做呢
本题由于时有序数组,所以重复元素一定是挨在一起的,本题就是查找 target 在 nums 中的左右边界。
- 若target在数组中,查找左右边界(关键);
- 若target在数组包含范围内,但不在数组中,返回[-1,-1];
- 若targer<nums[0]或target>nums[n-1],返回[-1,-1]
之前做过但是忘记了,对于边界的查找,我自己没有想出来,太菜了!!看卡哥的讲解
// - 若target在数组包含范围内,但不在数组中,返回[-1,-1];
// - 若target在数组中,查找左右边界(**关键:不要找target,转而找target的两边**);
// - 若targer<nums[0]或target>nums[n-1],返回[-1,-1]
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 mid = left + ((right - left) / 2);
if (nums[mid] > target) {
right = mid - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = mid + 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 mid = left + ((right - left) / 2);
if (nums[mid] >= target) {
right = mid - 1;
leftBorder = right;
} else {
left = mid + 1;
}
}
return leftBorder;
}
};
对于左右边界的选取,说直白一些就是不要找target,而是找target的两边。在普通二分查找中,当 nums[mid] == target 时,直接返回 mid,而在本题中,则是要继续向左或者向右查找,看是否还有和 target 相等的数组元素。所以在边界赋值的条件里总是包含 nums[mid]==target
27. 移除元素
解法一:暴力求解
对于本题,第一反应就是挨个遍历,找到重复的就将数组从后往前覆盖,然后继续向后遍历,直到遍历结束。注意在遍历过程中,覆盖完以后要将size-- && i--
。
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n=nums.size();
for(int i=0;i<n;i++){
if(nums[i]==val){
for(int ans= i+1; ans <n;ans++){
nums[i]=nums[ans];
}
i--;
n--;
}
}
return n;
}
};
解法二:双指针,快慢指针
本题详细讲解可以看卡哥讲解。
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
//快慢指针
int fast=0,slow=0;
while(fast<nums.size())
{
if(nums[fast]!=val)
{
nums[slow]=nums[fast];
fast++;
slow++;
}
else
{
fast++;
}
}
return slow;
}
};
拓展题随后有机会再联系。今日力扣学习三个小时,明天继续加油!