代码随想录训练营day01

1.二分法

二分法查找使用前提:有序数组,无重复元素

相关知识:vector的使用     动态分配数组    push_back,pop_back()

vector<int> v = {1, 2, 3};
v.push_back(4);                 // 添加 4
v.pop_back();                   // 删除最后一个元素
v.insert(v.begin(), 0);         // 在开头插入 0
v.erase(v.begin());             // 删除开头的元素
v.clear();                      // 清空所有元素
vector<int> v2 = {5, 6, 7};
v.swap(v2);                     // 交换内容

解题代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        while(left<=right){
            int middle=left+((right-left)/2);
            if(target==nums[middle])
            {
                return middle;
            }
            else if(target<nums[middle])
            {
                right=middle-1;
            }
            else if(target>nums[middle])
            {
                left=middle+1;
            }
        }
        return -1;
    }
};

易错点:1.循环条件left<=right,等于仍有效,当数组只有一个元素时

2.关于数组的溢出问题

3.关于数组的左闭右开,左开右闭问题

需要修改的点、

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

2.移除元素(经典解法)

采用快慢指针解题,移除数组元素

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow=0;
        for(int fast=0;fast<nums.size();fast++)
        {
            if(nums[fast]!=val)
            {
                nums[slow++]=nums[fast];
            }
        }
        return slow;
    }
};

注意点:1.return  slow代表返回新数组的长度

2.该算法实现的是nums.erase()的底层逻辑,要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

3.

  • 时间复杂度:O(n)    每个元素只被处理一次
  • 空间复杂度:O(1)   仍使用原数组储存新元素

3.有序数组的平方

题目链接:977. 有序数组的平方 - 力扣(LeetCode)

文章讲解:代码随想录

视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
      int  k=nums.size()-1;//新数组的最大索引
      vector<int> result(nums.size(),0);//首先定义一下要返回的数组
      int i=0;
      int j=nums.size()-1;
        while(i<=j)
        {
            if(nums[i]*nums[i]>nums[j]*nums[j])
            {result[k--]=nums[i]*nums[i];
            i++;}
            else 
            {
                result[k--]=nums[j]*nums[j];
                j--;
            }
        }
        return result;
    }
};

加深对双指针的认识

时间复杂度和空间复杂度

  1. 时间复杂度:O(n)

    • 双指针遍历整个数组,每个元素只被比较和处理一次。
  2. 空间复杂度:O(n)

    • 使用额外的数组 result 存储平方结果。

总结

可以使用双指针简化的题目:

1. 两端向中间收敛(对撞指针)

适用场景:

  • 处理有序数组或排序后的数组,解决与区间、和、积相关的问题。
  • 主要用于查找满足某种条件的两个元素或多组元素。

典型问题:

  1. 求和问题:

    • 两数之和(Two Sum) 的变种:数组有序,求两个数的和等于目标值。
    • 思路: 用两个指针分别从数组两端向中间移动,调整两指针的和,直到找到目标值。
      int twoSum(vector<int>& nums, int target) {
          int left = 0, right = nums.size() - 1;
          while (left < right) {
              int sum = nums[left] + nums[right];
              if (sum == target) return {left, right};
              else if (sum < target) left++;
              else right--;
          }
          return {};
      }
      
    • 三数之和问题:

      • 三数之和(Three Sum):找到数组中三数相加等于零的所有组合。
      • 思路: 固定一个数字,然后对剩下的数组使用对撞指针寻找两数之和。
    • 有序数组中的平方排序:

      • 977. 有序数组的平方
      • 思路: 从数组两端开始比较平方值,将较大的平方值放入结果数组的尾部。

2. 快慢指针(双指针中的一快一慢)

适用场景:

  • 用于在数组或链表中查找循环、跳跃、间隔等问题。
  • 常用于判定某些条件是否成立,例如是否有环、元素位置重排、过滤等。

典型问题:

  1. 移除元素:

    • 27. 移除元素:删除数组中所有等于某值的元素,返回剩下元素的长度。
    • 思路: 快指针遍历数组,慢指针记录有效元素的下标,快指针将非目标元素赋值到慢指针处。
  • 判断链表是否有环:

    • 141. 环形链表
    • 思路: 快慢指针,快指针每次走两步,慢指针每次走一步。如果链表有环,快慢指针最终会相遇。
  • 寻找链表的中间节点:

    • 思路: 快指针一次移动两步,慢指针一次移动一步,当快指针到达链表末尾时,慢指针正好在中间位置。
  • 3. 滑动窗口(窗口双指针)

    适用场景:

  • 主要用于处理子数组或子字符串的问题,例如求固定窗口大小的最值、最优子区间等。
  • 窗口是动态调整的,窗口的范围由两个指针控制。
  • 等.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值