代码随想录算法训练营第一天 | LeetCode704.二分查找、LeetCode27.移除元素

代码随想录算法训练营第一天 | LeetCode704.二分查找、LeetCode27.移除元素

704.二分查找

题目链接:704.二分查找

思路:

  • 设置两个逻辑指针,指向数组的头尾两个元素;
  • 判断它们中间的值和目标元素的关系:
  • 若目标元素更大,则在这个中间值的左侧子数组中,若小则相反,若相等则返回当前地址;
  • 若前后指针指向同一位置时还未找到则返回不存在

时间复杂度:O(logn),空间复杂度O(1)

代码:

class Solution
{
public:
    // 左闭右闭
    int search(vector<int> &nums, int target)
    {
        int front = 0;
        int back = nums.size() - 1;
        while (front <= back)
        {
            int mid = front + (back - front) / 2;
            if (nums[mid] < target)
            {
                front = mid + 1;
            }
            else if (nums[mid] == target)
            {
                return mid;
            }
            else
            {
                back = mid -1;
            }
        }
        // 只要数组内有target元素,必定会在while循环中找到并return
        return -1;
    }
};

总结:

  • 二分查找基本练习,算是热身,后面maybe有一些题需要用到这个思路,最好能达到快速默出来
  • 做题体验:哈哈哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:未计
  • 一刷

27.移除元素

题目链接:27.移除元素

思路废话:

  • 这题我的思路和代码随想录的文章中有所出入:
  • 要求:将值为val的数移除,原地修改
  • 若数组有n个数,val值由r个,处理过后不为val的n-r个值都要放在数组前n-r的位置上
  • 我就想到了用交换位置的想法,将值为val的数都扔到数组后侧。

思路:

  • 用一个双指针,指向数组头尾(和上面一题很像哦)
  • 头指针负责判断当前元素是否为val,如果是则交换
  • 而尾指针负责记录接下来应该交换的数组尾的位置,每交换一次就往前移一位
  • 头尾指针相遇则结束,相遇的位置就是移动完之后第一个val的的位置,也代表了所求数组的长度
  • (更多细节看代码注释)

时间复杂度:O(n),空间复杂度O(1)

代码:

class Solution
{
public:
    int removeElement(vector<int> &nums, int val)
    {
        int front = 0;
        int back = nums.size() - 1;
        while (front < back)
        {
            if (nums[front] == val)
            {
                // 有可能从数组尾换回来的还是一个val
                // 头指针留在原地下一轮再判断一次
                swap(nums[front], nums[back]);
                --back;
            }
            else
            {
                ++front;
            }
        }
        if (nums.size() != 0) // 如果数组本身为空,使用索引会越界
        {
            // 当头尾指针相遇的时候,如果指向的元素不是val
            // 则还要向后退一位指向第一个val
            if (nums[front] != val)
                ++front;
        }
        return front;
    }

    void swap(int &a, int &b)
    {
        int tep = a;
        a = b;
        b = tep;
    }
};

总结:

  • 这题昨天刚做过,今天几乎直接就默出来了,下午在上班,没来的及理解一下carl哥的思路[TODO],留作周末作业吧
  • 做题体验:嘿嘿
  • 时间:未计
  • 二刷

34.在排序数组中查找元素的第一个和最后一个位置[补充]

题目链接:34.在排序数组中查找元素的第一个和最后一个位置

思路:

  • 以704的基本框架为基础
  • 找到任意一个target的位置
  • 然后向前,向后遍历找到第一次和最后一次出现的位置

时间复杂度:O(n),空间复杂度O(1)

代码:


class Solution
{
public:
    vector<int> searchRange(vector<int> &nums, int target)
    {
        std::vector<int> res = {-1, -1};
        auto length = nums.size();
        if (length == 0)
            return res;
        int front = 0;
        int back = length - 1;
        int mid;
        bool hasTarget = false;
        while (front <= back)
        {
            mid = front + (back - front) / 2;
            if (nums[mid] < target)
            {
                front = mid + 1;
            }
            else if (nums[mid] == target)
            {
                hasTarget = true;
                break;
            }
            else
            {
                back = mid - 1;
            }
        }
        if (!hasTarget)
            return res;
        res[0] = mid;
        res[1] = mid;
        for (int i = mid - 1; i >= 0; i--)
        {
            if (nums[i] != target)
            {
                res[0] = i + 1;
                break;
            }
            else
            {
                res[0] = i;
            }
        }
        for (int i = mid +1; i < length; i++)
        {
            if (nums[i] != target)
            {
                res[1] = i-1;
                break;
            }
            else
            {
                res[1] = i;
            }
        }
        return res;
    }
};

总结:

  • 这题做得太拉跨咯,写完博客看一下好的题解吧[TODO],这样才算做完
  • 原本是想找到任意个target之后,对当前位置的左右两个子数组再进行一次二分查找,找到非target值和target值的分界线,这样算法的时间复杂度是3longn,也属于O(logn)级别的,但临界情况和数组越界问题调了一个小时也没调通。发现LeetCode上的测试案例的数组长度并不大,改用遍历
  • 做题体验:嘤嘤
  • 时间:未计
  • 一刷

35.搜索插入位置[补充]

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

思路:

  • 以704的基本框架为基础
  • 遍历之后若没找到元素,则插在当前头指针位置

时间复杂度:O(n),空间复杂度O(1)

代码:

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

总结:

  • 第一次刷的时候对跳出while循环之后,直接返回front不是太理解,写的有点复杂
  • 其实跳出循环只有两种情况:、
    • nums[mid] < targetfront = mid + 1导致front <= back跳出循环。
      当前front索引位置的值大于target,前一个位置小于target,所以应该返回当前的front。另一种情况比较好理解不说了。
  • 做题体验:嘿嘿
  • 时间:未计
  • 二刷,昨天刚跟按照公众号文章做过这一题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值