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

目录

数组理论基础

704.二分查找

27.移除元素

1.暴力解法:

2.双指针法

3.相向双指针法(只在文章里面有)

今日收获


数组理论基础

二维数组在c++的地址空间是连续的,假设我们建立一个int array[2][3],输入&array[0][0]和&array[0][1] 返回的都是里面存储的整数型数据指向内存的起始地址,这两个相邻地址的十六进制内存大小会差4,因为存储的整数型int数据是4个字节。

704.二分查找

题目链接:

 底层逻辑:在数组中寻找target,没有找到就返回-1

看完楼上的视频,按照自己的思路顺了一遍,然后和老师的板书一对没问题,那看来是懂了

左闭右闭

left = 0

right = num.size-1

while(left < = right )//如果是一个闭区间,那么左右都是相同的值是合理的,比如[1,1]代表的是从1到1闭区间

        middle = (left + right) /2

        if(middle > target)//target在middle的左面,需要更换右边界

                right = middle - 1 //闭区间的话就不包含已经大了的middle

        elseif(middle < target)//target在middle的y右面,需要更换左边界

                right = middle + 1 //闭区间的话就不包含已经小了的middle

        else return middle

左闭右开

left = 0

right = num.size //需要比最后一位的位置高1,不然无法取到最后一位

while(left < right  )//如果是一个右开区间,那么左右都是相同的值不再是合理的,比如[1,1)

        middle = (left + right) /2

        if(middle > target)//target在middle的左面,需要更换右边界

                right = middle //开区间因为取不到middle,所以可以设置成middle

        elseif(middle < target)//target在middle的右面,需要更换左边界

                right = middle + 1 //闭区间的话就不包含已经小了的middle

        else return middle

 我写的错误代码和分析:

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

1.不应该用middle和target比大小,应该是用下标为middle的数组里面的数

2.我混淆了输出的概念,如果在while循环里面,最后一种情况是nums[middle] == target,也就是else,我把这两个混淆成了一个概念,如果相等就return nums[middle]

3.左闭右闭是nums.size()-1,在笔记里写的挺好,一写真代码就有问题

4.如果在while循环中没有找到相应的数据,那么需要在外面写return -1;

一开始没写的时候,有这样的错误

non-void function does not return a value in all control paths

这是一个编程错误,表示非空函数在所有控制路径上都没有返回值。这意味着在函数的所有执行分支中都没有返回语句。应该在每个分支中添加一个返回语句,以确保在所有情况下都返回值。

 对的结果:左闭右闭

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)/2;
            if(nums[middle] < target){
                left = middle + 1;
            }else if(nums[middle] > target){
                right = middle -1;
            }else{
                return middle;
            }
        }
        return -1;
    }
};

27.移除元素

数组是一个连续的类型相近的数据的集合,删除数组中的元素是不可行的,只能让后面的元素上来进行覆盖

举个例子:

当你想删除3的时候,用erase操作,这是一个O(N)的操作其实是4和5上来补位,这个时候你再调用vector.size(),返回的是4,可是表格的内存空间占的地方还是5 

1.暴力解法:

用for循环遍历列表,当出现相等的数值时,用后边的数据覆盖前面的数据,然后需要i-1,因为下一位数据已经被放在了上一个被删除数据的位置上,size-1,因为我们删除了这个相等的数据

我的错误代码分析:

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

};

 错误分析:

1.如果想要遍历整个表格,也就是下标从0到size-1,那么应该是i<size

2.第二个for循环的遍历应该是 j=i+1,这样可以少一个遍历的数据

正确代码:

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

};

2.双指针法

数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili

首先需要有两个指针,一个slow,一个fast,fast是用来遍历整体的数组元素,slow是新的数组的下标位置

slow = 0

for (fast = 0; fast < size; fast ++)

        if(nums[fast] != val)

                nums[slow] = nums[fast];

                slow++;

//如果指向的这个新数组元素等于我们需要的值,那么就是删除操作,这里就是新数组的下标不变,会把下一个不等于val的数组元素放到这里

//快指针会一直+1,做到遍历数组元素,slow只有在满足相应条件的时候才+1

//最后slow会加1,所以就是size了

  代码展示:

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

};

注意:也可以把slow++放到num[]里面,是一样的效果

3.相向双指针法(只在文章里面有)

我的代码报错:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        int left = 0;
        int right = size - 1;
        while(left <= right){
            //用左指针找到从左面起不等于val的值
            while(nums[left] != val){
                left++;
            }
            //用右指针找到等于val的值
            while(nums[right] == val){
                right++;
            }
            if(left < right){
                nums[left++] = nums[right++];
            }
        }
        //在找到最后一个val的值的时候,左指针会跳到下一个
        return left;
    }

};

 报错原因:
1.AddressSanitizer 被用来检查内存的非法访问,在 leetcode 中出现 AddressSanitizer: heap-buffer-overflow on address 类似报错,主要原因可能是存在数组越界

---> 应该是right--,写成++了

2.

 因为左右两个指针的while都没有left<=right,这样会反复加

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        int left = 0;
        int right = size - 1;
        while(left <= right){
            //用左指针找到从左面起不等于val的值
            while(left <= right && nums[left] != val){
                left++;
            }
            //用右指针找到等于val的值
            while(left <= right && nums[right] == val){
                right--;
            }
            if(left < right){
                nums[left++] = nums[right--];
            }
        }
        //在找到最后一个val的值的时候,左指针会跳到下一个
        return left;
    }

};

今日收获:

今天终于完成了代码随想录day1的内容,虽然说看上去好像很简单,但是由于我并没有算法的基础,还对c++的语言掌握得不太熟练,又学习算法又学习c++的语法,所以付出了比别人更多的时间和心血,但是!我至少搞完了!我觉得自己很棒!

学习时长:6h

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值