【C++编程能力提升】

代码随想录训练营Day1 | Leetcode704二分查找、leetcode27移除元素

  • 一、704--二分查找
    • 1、二分查找--左闭右闭
    • 2、二分查找--左闭右开
  • 扩展:35--搜索插入位置
    • 1、二分查找-左闭右闭
    • 2、二分查找--左闭右开
  • 二、27--移除元素
    • 1、暴力法
    • 2、双指针法--左右指针
    • 3、双指针--快慢指针

一、704–二分查找

题目链接:704、二分查找

前提:元素有序,存在已知target;
核心:确定与target比较后针对不同情况的处理,比如等于target、小于target和大于target;
途径:左闭右闭 + 左闭右开,不同解决途径对于不同情况的处理是不同的,主要体现在开区间元素是无意义的,即无法可取。

1、二分查找–左闭右闭

    int left=0;
    int right=nums.size()-1;
    while(left<=right)
    {
        int mid = left+(right-left)/2;
        if(nums[mid]==target)
            return mid;
        else if(nums[mid]>target)
            right=mid-1;
        else 
            left=mid+1;
    }
    return -1;

2、二分查找–左闭右开

    int left=0;
    int right=nums.size();
    while(left<right)
    {
        int mid=left+(right-left)/2;
        if(nums[mid]==target)
            return mid;
        else if(nums[mid]>target)
            right=mid;//注意右开时right是取不到该值的,故只能为mid,而不能为mid-1
        else 
            left=mid+1;
    }
    return -1;

扩展:35–搜索插入位置

题目链接:35、搜索插入位置

1、二分查找-左闭右闭

    int left=0;
    int right=nums.size()-1;
    while(left<=right)
    {
        int mid=(right-left)/2+left;
        if(nums[mid]==target)
            return mid;
        else if(nums[mid]>target)
            right=mid-1;
        else 
            left=mid+1;
    }
    return left;

2、二分查找–左闭右开

    int left=0;
    int right=nums.size();
    while(left<right)
    {
        int mid=(right-left)/2+left;
        if(nums[mid]==target)
            return mid;
        else if(nums[mid]>target)
            right=mid;
        else
            left=mid+1;
    }
    return left;

二、27–移除元素

题目链接:27、移除元素

核心:针对数组元素的移除,只能令有效元素覆盖无效元素。
方法:无效元素移至数组末尾,可以逐个元素移动,也可以首尾元素移动;或者仅在有效数组中添加有效元素,即将有效元素移至数组起始,这样也能使无效元素位于数组末尾。

1、暴力法

思想是:两层for循环,外层遍历原数组元素;当遇到需移除的无效元素时,内层for循环从该无效元素的下一个元素开始,逐个覆盖前一个元素直到有效数组的最后一个元素,实质是将无效元素移到末尾;否则,即遇到有效元素则无需处理。
注意1:移除无效元素后,即更新数组后的i指向原数组的i+1,故需i–后再次判断i处元素是否有效;
注意2:移除无效元素后,有效数组的长度也需要更新。

    int len=nums.size();
    for(int i=0;i<len;++i)
    {
        if(nums[i]==val)
        {//遇到val需移除此nums[i],即i+1开始的元素需前移一位,覆盖前一位的元素
            for(int j=i+1;j<len;++j)
            {//更新结束后,此时nums size=j
                nums[j-1]=nums[j];
            }
            i--;//更新后的i指向原来的i+1处,故仍需再次判断nums[i]
            len--;//移除一个即长度减一
        }     
    }
    return len;

2、双指针法–左右指针

思想是:令left和right分别指向有效数组的首尾元素,left指针遍历有效数组元素,一旦left指向无效元素,则与right指向元素相互交换,交换后right指向无效元素,故需更新right,即right前移一位(交换后仍需判断当前left指向元素,故此时left无需后移);否则,即left指向元素是有效的,left右移继续遍历,直至left>right遍历结束。
注意:right总是指向最后一个有效元素,故有效数组长度为right+1,即left。

    int left=0;
    int right=nums.size()-1;
    while(left<=right)
    {//左闭右闭
        if(nums[left]==val)
        {//遇到val时交换right元素与left元素,以及right前移(因为交换后的right元素是移除的
            nums[left]=nums[right];
            nums[right]=val;
            right--;
        }
        else
            left++;  
    }
    return left;//最终返回有效数组长度right+1(right指向最后一个有效元素),即left

3、双指针–快慢指针

思想是:设置slow和fast指针,fast遍历原数组元素,slow指向有效数组的元素。
当fast指向元素有效时,添加到slow指向的有效数组中,即赋值给slow,并且slow后移一位,准备接收下一个有效元素;否则,即fast指向元素无效时,继续遍历,无需对slow进行处理。

    int slow=0;
    for(int fast=0;fast<nums.size();++fast)
    {
        if(nums[fast]!=val)
        {//fast指向元素有效,则赋值给slow,且slow后移一位
            nums[slow]=nums[fast];
            slow++;
        }
    }
    return slow; //返回slow不是slow+1是因为slow指向下一个有效元素

你可能感兴趣的:(C++编程,c++,leetcode)