0


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

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

数组理论基础

文档讲解:数组理论基础
视频讲解:暂无
状态:😀

数组要点
  • 数组是存放在连续内存空间的相同类型数据的集合。
  • 数组的下标都是从0开始的。
  • 数组内存空间的地址是连续的。
  • 数组中的元素不能删除,只能进行覆盖。

所以增删元素的时候需要对其他元素的地址做相关操作。

C++相关
  • 在C++中,vector和array存在区别,vector的底层实现是array,严格来说vector是容器,不是数组。
  • 在C++中,二维数组在内存空间上是连续分布的。

704.二分查找

题目链接:704. 二分查找
文档讲解:704. 二分查找
视频讲解:二分查找法
目标:熟悉根据 左闭右开,左闭右闭 两种区间规则 学出来的二分法
状态:以前的方法全都忘记了,边界条件含糊不清,还是要多总结

学习前的想法

因为平常也了解过一些简单的算法,加上学校上课提到的,二分查找的基本思想我是了解的,只需不断的将区间的中位数与目标值作比较,选择左右区间,直到找到目标值或数组越界。

尝试写出代码如下(错误):

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int length = nums.size() - 1;

        while (length < nums.size() && length > -1) {
            if (nums[length] == target)
                return length;

            if (nums[length] > target) {
                length--;
                length -= length / 1;
            }

            if (nums[length] < target) {
                length++;
                length += (nums.size() - 1 - length) / 1;
            }
        }

        return -1;
    }
};

代码超时!

反思之后,在写题时对边界条件没有很好的理解,导致浪费了大量时间还没写对。

2024/2/21
个人并没有看出代码是在哪里出错,可能是循环终止条件有问题。🥲

学习后的想法

二分法的关键是处理好边界问题,包括:循环边界,区间边界

一般来说,我们采用的有两种边界取法,左闭右闭,左闭右开,以left和right分别表示数组的边界,即

[left, right]

[left, right)

在二分法中,有两处需要判断边界,一处为

while

循环的终止条件,另一处为选择边界时

left

或者

right

middle

的取值。

我们在解决这类问题时,需要选择上述所说的一种区间,然后一路走到底。对于每处边界判断,都要以我们所选定的区间来取舍,来判断进行选择后取值是否符合区间范围。

卡哥讲的很清楚,确实是让我理解了这个边界选择的方法,以前看acwing的视频没有理解为什么,只背了模板,结果时间长了模板忘了,题也做不对了。

实现

左闭右闭

// 区间左闭右闭,[left, right]
left = 0;
right = nums.size() - 1;

// left==right时,区间[left, right]依然有效,所以用<=
while(left <= right) {
    // 使用 middle = left + ((right - left) / 2)可以防止溢出
    middle = (left + right) / 2;
    
    if(nums[middle] > target) right = middle - 1; // 左区间,[left, middle - 1]
    else if(nums[middle] < target) left = middle + 1; // 右区间,[middle + 1, right]
    else return middle;// 找到目标值,将其返回
}

// 未找到目标值
return -1;

左闭右开

// 区间左闭右闭,[left, right)
left = 0;
right = nums.size();

// left==right时,在区间[left, right)无效,所以用<
while(left < right) {
    // 使用 middle = left + ((right - left) / 2)可以防止溢出
    middle = (left + right) / 2;
    
    
    if(nums[middle] > target) right = middle; // 左区间,[left, middle)
    else if(nums[middle] < target) left = middle + 1; // 右区间,[middle + 1, right)
    else return middle; // 找到目标值,将其返回
}

// 未找到目标值
return -1;

27.移除元素

题目链接:27.移除元素
文档讲解:27. 移除元素
视频讲解: LeetCode:27. 移除元素
状态:暴力法能够解决,不过还是不熟练,双指针法确实开拓了思路

学习前的想法

题目给出了一个数组中

nums

和一个值

val

,要求

原地

移除所有数值等于val的元素,并返回移除后数组的新长度。

原地算法,即空间复杂度为O(1)

暴力法(双层

for

循环):我的想法是遍历数组,遇到与

val

相等的值,则将后续所有元素向前移动一位,接着从当前位置继续遍历,并将数组长度减一。

代码实现:

// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int length = nums.size();

        if(length == 0) {
            return 0;
        } else {
            for(int i = 0; i < length; i++) {
                if(nums[i] == val) {
                    for(int j = i; j < nums.size() - 1; j++) {
                        nums[j] = nums[j + 1];
                    }

                    length--;
                    i--;
                }
            }
        }

        return length;
    }
};

2024/2/21
和卡哥的代码对比,for循环前对length==0的判断似乎没有必要

学习后的想法

题外话:有关库函数的使用问题
卡哥的建议:如果一道题目使用库函数可以直接解决,不建议使用;如果使用库函数知识解决这个问题的其中一小步,并且我们直到这个库函数内部的实现过程,以及它的时间复杂度,可以用。

vector.erase()
作用:删除元素
原理:将后面元素向前移,将删除元素覆盖
时间复杂度:O(n)

使用双指针法可以达到O(n)的时间复杂度,仅使用一层for循环:

快指针:声明为

fast

,初始值为0,用于遍历数组,找到所有不等于目标元素,应该保留的值。

慢指针:声明为

slow

,初始值为0,相当于指向一个空的、新的数组,不断的填入快指针找到的值。

流程:
当快指针指向的值符合条件时,即不等于

val

时,将该值赋给慢指针指向的位置,

fast++; slow++;

当快指针指向的值不符合条件,即等于

val

时,跳过该元素不赋值,

fast++; slow不变;

最终,当快指针遍历完数组时,慢指针指向其所表示新数组的最后一个元素的后一位,由于其值从0开始,因此慢指针的位置便是新数组的长度。

实现过程记录
// 时间复杂度:O(n)
// 空间复杂度:O(1)
int slow = 0;

// 快指针遍历数组(一个for循环)
for(int fast = 0; fast < nums.size(); fast++) {
    if(nums[fast] != val) {
        nums[slow++] = nums[fast];
    }
}

return slow;

收获与学习时长

学习时长:3h45min

收获

熟悉了 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。

掌握双指针法解决移除元素。(相向双指针暂时没有手敲,思路时使用左右指针进行遍历)

标签: 算法

本文转载自: https://blog.csdn.net/m0_64615322/article/details/136222096
版权归原作者 zoney hu 所有, 如有侵权,请联系我们删除。

“代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素”的评论:

还没有评论