您的位置:首页 > 文旅 > 旅游 > 最好看免费观看高清大全大江大河_东营志愿服务网_色盲_miy188coo免费入口

最好看免费观看高清大全大江大河_东营志愿服务网_色盲_miy188coo免费入口

2025/4/18 16:04:29 来源:https://blog.csdn.net/m0_74696257/article/details/147091629  浏览:    关键词:最好看免费观看高清大全大江大河_东营志愿服务网_色盲_miy188coo免费入口
最好看免费观看高清大全大江大河_东营志愿服务网_色盲_miy188coo免费入口

704. 二分查找 - 力扣(LeetCode)

关于二分查找

  • 最重要的是要处理好边界问题,每次写完边界可以带入特殊值进行测试
  • 确定区间的不变量是什么?比如区间的左闭右闭,和左闭右开,每次二分完的新区间,一定要一直和最开始的区间的定义保持一致,要时刻明确区间的含义
  • 注意二分的几种情况(当数组长度为n的情况下)
    • 当l = 0, r = n的时候因为r这个值我们在数组中无法取到,while(l < r) 是正确写法
    • 当l = 0, r = n - 1的时候因为r这个值我们在数组中可以取到,while(l <= r) 是正确写法 主要看能不能取到这个值
  • 注意处理二分mid溢出的问题
    • 当l 和 r 较大时,mid = (l + r) / 2 可能会出现大于INT_MAX的情况,会溢出。
    • 可以写成 mid = l + (r - l) / 2  或者 mid = l + ((r - l) >>1)的形式

思路:这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。

一开始的代码:

class Solution {
public:int search(vector<int>& nums, int target) {int size = nums.size();int l = 0, r = size - 1;while(l < r){int mid = (l + r) >> 1;if(nums[mid] < target)l = mid+1;elser = mid;}if(nums[r] != target)return -1;return r;}
};

这个代码可以解决数组中存在重复元素的情况,但是要注意的点有许多,第一个 l < r 当我写成 l <= r 时会死循环,因为当r = l时,进去循环,会一直r = mid 不能跳出循环,导致死循环还是要注意,这可能是不规范的写法吧。

下面有两个规范的模版(只能用于严格的升序排序,不能出现相同的元素,如果目标元素出现多次就不能正确的返回下标

左闭右闭

class Solution {
public:int search(vector<int>& nums, int target) {int size = nums.size();int l = 0, r = size - 1;while(l <= r){int mid = l + ((r - l) >> 1);if(nums[mid] < target)//mid 小于就去mid的右面去找,并且mid不为targetl = mid+1;else if(nums[mid] > target)//mid 大于就去mid的左面去找,并且mid不为targetr = mid-1;else//就是 mid = target 的情况,所以直接返回mid就可以了return mid;}//没有在循环中返回说明,没有找到目标,返回-1return -1;}
};

左闭右开

class Solution {
public:int search(vector<int>& nums, int target) {int size = nums.size();int l = 0, r = size;while(l < r)    // r不能取到,l = r 没有意义{int mid = l + ((r - l) >> 1);if(nums[mid] < target)//mid 小于就去mid的右面去找,并且mid不为targetl = mid+1;else if(nums[mid] > target)//mid 大于就去mid的左面去找,并且mid不为target,但是区间不包含mid 所以 r = midr = mid;else//就是 mid = target 的情况,所以直接返回mid就可以了return mid;}//没有在循环中返回说明,没有找到目标,返回-1return -1;}
};

其实二分还有很多应用场景,有着许多变体,比如说查找第一个大于target的元素或者第一个满足条件的元素,都是一样的,根据是否满足题目的条件来缩小答案所在的区间,这个就是二分的本质。另外需要注意,二分的使用前提:有序数组

27. 移除元素 - 力扣(LeetCode)

 我的思路(对撞指针)

        题目要求返回不等于val的个数和nums数组,我们只需要考虑返回数组前面的部分是不等于val的就可以,所以这道题的解法是双指针(对撞的),现从前面开始,如果不等于就走,等于之后 右指针在走,右指针找到不等于val的数字,与左指针指向的数字互换

class Solution {
public:int removeElement(vector<int>& nums, int val) {int l = 0, r = nums.size()-1;//如果为空直接返回0if(l > r)   return 0;while(l < r){if(nums[l] != val)l++;else{if(nums[r] != val){int tmp = nums[r];nums[r] = nums[l];nums[l] = tmp;}r--;}}//循环出来一定是 l = r 再判断 l=r时等不等于valif(nums[l] == val)  //因为返回的是个数return l ;elsereturn l+1;}
};

暴力解:

一开始要求暴力解第一时间还真没想到,后来看到题解,才想到的暴力解。

 数组中元素不能删除只能进行覆盖,所以暴力的解法就是从前往后遍历,找到val然后用后面的元素将val进行覆盖,同时将nums数组的长度减减,最后返回记录好的数组长度就可以了。

class Solution {
public:int removeElement(vector<int>& nums, int val) {int size = nums.size();for(int i = 0; i < size; i++){if(nums[i] == val){//val 后面的元素覆盖val都向前进行覆盖for(int j = i+1; j < size; j++){nums[j-1] = nums[j];}//交换之后,后面数组向前覆盖,不知道后面数字是不是等于val然后要再一次判断是不是等于vali--;//每覆盖一次就要size--size--;}}return size;}
};

 双指针(同向指针 \ 快慢指针)

快指针可以理解成在旧数组中找非目标元素,然后赋值给慢指针指向的新数组,虽然都指向一个数组

  • 关于二分法和移除元素的共性思考 这两题之间有点类似的,他们都是在不断缩小 left 和 right 之间的距离,每次需要判断的都是 left 和 right 之间的数是否满足特定条件。对于「移除元素」这个写法本质上还可以理解为,我们拿 right 的元素也就是右边的元素,去填补 left 元素也就是左边的元素的坑,坑就是 left 从左到右遍历过程中遇到的需要删除的数,因为题目最后说超过数组长度的右边的数可以不用理,所以其实我们的视角是以 left 为主,这样想可能更直观一点。用填补的思想的话可能会修改元素相对位置,这个也是题目所允许的。
  •  fast < nums.size()fast <= nums.size()-1 没什么区别,那为什么第二个会在空数组时报数组越界的错误? vector的size()函数返回值是无符号整数,空数组时返回了0,再减个一会溢出;变成一个很大的正数,nums[fast] 会发生 null pointer of type 'int' 异常。

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

所以思路就是,快指针在前面寻找不是目标元素的元素,慢指针可以理解为用来维护新数组,也就是不含目标元素的数组,如果不等于val 快慢指针都++,等于慢指针用来记录val的位置,快指针向后寻找不等于val的值与慢指针的val进行交换,直到快指针走到最后

class Solution {
public:int removeElement(vector<int>& nums, int val) {int l = 0, r = 0;//r 每一步都要走for(int i = r; i < nums.size(); i++){//可以理解为,i为一个符合条件的数组,不等于val就往里面加if(nums[i] != val)nums[l++] = nums[i];}// l 就为新数组的长度return l;}
};

 977. 有序数组的平方 - 力扣(LeetCode)

思路:看到这道题,我首先想到的是,将他们的平方都放入数组中,然后进行排序,这种时间复杂度比较高的暴力解法。后面自己想了一下可不可以使用一个时间复杂度为O(1)的方法解出来呢,一开始想用双指针,每个分别用来记录一个数组,比较然后先比较在插入,发现最后回到了插入排序的思想。

先看看暴力解法

class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {for(int i = 0; i < nums.size(); i++){nums[i] = nums[i]*nums[i];}sort(nums.begin(), nums.end());return nums;}
};

 可以发现虽然通过了,但是方法还是不太好。

双指针

        我们发现有负数和正数,我们不能判断负数和正数谁的平方谁更大(为什么判断谁更大呢,因为数组是从小到大排的,负数越小平方就越大,看到这,我们可不可以先开一个一摸一样大小的数组,然后用两个指针分别记录数组两端平方较大的值呢,谁更大谁就先从后往前插入)

class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {int size =nums.size();int l = 0, r = nums.size()-1;//开一个新数组vector<int>a(nums.size());//x 用来为数组下标int x = size-1;while(l <= r){//右面大,右面赋值if(nums[l]*nums[l] < nums[r]*nums[r]){a[x--] = nums[r]*nums[r];r--;//指针向左移}    else{//左面大,左面赋值a[x--] = nums[l]*nums[l];//左指针右移l++;}}return a;}
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com