赞
踩
- class Solution {
- public:
- int search(vector<int>& nums, int target) {
- int left = 0;
- int right = nums.size() - 1; //定义target的区间左闭右闭,[left,right]
- while (left <= right){
- int middle = left + ((right - left) / 2); //防止溢出
- if (nums[middle] > target){
- right = middle - 1;
- }
- else if (nums[middle] < target){
- left = middle + 1;
- }
- else{
- return middle;
- }
- }
- //未找到目标值
- return -1;
- }
- };
二分查找主要是要注意自己的代码是左闭右闭还是左闭右开,也就是第一点:left = right是否合法,第二点:nums[middle]不是搜索值,这时候再看是右开还是右闭,闭区间的right值能搜索到所以不能等于right值,反之右开区间可以。
还有点小细节就是可以用位运算:>>1 去替换 / 2,这样运算速度会更快。
以704为母题,34、35和704也是一类题。特点是先判断target值在数组中的位置情况,其中35要求时间复杂度为O(log n), 其实遇到这类暗示一般都会想到用二分法查找, 具体情况如下:
- class Solution {
- public:
- int searchInsert(vector<int>& nums, int target) {
- int n = nums.size();
- int left = 0;
- int right = n - 1;
- while (left <= right) { //当区间为[left, right]时仍然有效
- int middle = left + ((right - left) / 2);
- if (nums[middle] > target) {
- right = middle - 1;
- }
- else if (nums[middle] < target) {
- left = middle + 1;
- }
- else { //nums[middle] == target
- return middle;
- }
- }
- // 处理四种情况
- // 目标值在数组所有元素之前 [0 , -1]
- // 目标值等于数组中的某个元素, return middle;
- // 目标值插入数组中的位置 [left , right], return right + 1;
- // 目标值在数组所有元素后, return right + 1;
- return right + 1;
- }
- };
而34题更复杂一点,由于数组中有重复的目标值,需要去找目标值的左边界和右边界,通过给左右边界赋值去判断目标值是否在数组范围中:
- class Solution {
- public:
- vector<int> searchRange(vector<int>& nums, int target) {
- int leftBorder = getLeftBorder(nums, target);
- int rightBorder = getRightBorder(nums, target);
- // target不在数组范围中
- if(leftBorder == -2 || rightBorder == -2) return {-1, -1};
- // target在数组范围中且数组存在target
- if(rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
- // target在数组范围中但是数组不存在target
- return {-1, -1};
- }
- private:
- int getRightBorder(vector<int>& nums, int target) {
- int left = 0;
- int right = nums.size() - 1; // 定义target在左闭右闭的区间内,[left,right]
- int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
- while(left <= right){
- int middle = left + ((right - left) / 2); //防止溢出
- if (nums[middle] > target){
- right = middle - 1;
- }
- else{
- // 当nums[middle] == target时,才得到target的右边界
- left = middle + 1;
- rightBorder = left;
- }
- }
- return rightBorder;
- }
- int getLeftBorder(vector<int>& nums, int target) {
- int left = 0;
- int right = nums.size() - 1; // 定义target在左闭右闭的区间内,[left,right]
- int leftBorder = -2; // 记录一下rightBorder没有被赋值的情况
- 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;
- }
- };
注:关于二分查找最好画个数轴,直观一些。
lc27.移除元素 给一个数组,一个目标值,在数组中删除等于这个目标值的元素,返回新数组的大小。
这个题最关键的底层逻辑是数组中的元素不能删除,只能覆盖。如果用暴力法就是先遍历数组,再赋下标值。通过双指针的思路,把快指针记录的新数组中所需的元素值赋给慢指针,而慢指针的作用是获取新数组中需要更新的位置,遇到相同值的元素时不更新慢指针的位置进入下个循环。
- class Solution {
- public:
- int removeElement(vector<int>& nums, int val) {
- int slowIndex = 0;
- for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++){
- if (val != nums[fastIndex]){
- nums [slowIndex++] = nums [fastIndex];
- }
- }
- return slowIndex;
- }
- };
与27题相关的题还没做,明天一并更新。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。