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

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

1.了解数组基础

数组是存放在连续的内存空间,相同类型数据的集合

数据类型:相同的数据类型

存储方式:存放在连续的内存空间中

因为是存放在连续的内存空间中,数据之间是紧挨着的,所以删除元素和插入元素需要移动指定位置之后的所有数据。(存储方式决定了元素的操作)

数组元素的删除是通过元素覆盖

获取元素:通过数组下标索引

数组下标从0开始

2.LeetCode 704.二分查找

题目链接:https://leetcode.cn/problems/binary-search/

2.1自己看到题目的第一想法

思路1:暴力解决,用for循环遍历与目标值相同的元素,返回下标

思路2:二分查找

二分查找适用:主要用于一个有序的数组(元素之间),查找目标值。

二分查找思想:对数据进行折半查找,用左右指针(两个变量)对中间的下标进行控制(也成为一个变量)。中间值等于目标值,就返回中间值下标,反之继续更新中间值,直到左指针大于右指针证明数组元素已全部遍历过,还没有等于目标值,证明数组中没有这个元素,返回-1。

代码:

精简版:

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

解析版:

class Solution {
    public int search(int[] nums, int target) {
        //目标值变量target

        //问题分解
        //1、对半砍,数组中最中间的值是哪一位元素(是一个会变得量,那我们就先定义出来)
        int mid;
        //2、找指定元素
        //3.2需要左右元素,是一个变化得值,定义出来
        int left=0;
        int right=nums.length-1;
        //for(int i=0;i<nums.length;i++){
            //3.需要左右元素
            
        //}
        mid=(left+right)/2;//中间值得元素下标
        //那我们希望,当nums[mid]!=target的时候(大于或者小于),要变化mid的值,也就要变化left或者right的值
        //要排除right>left的风险,这时就说明所有元素已经遍历完了,依旧没找到,返回-1
        while(left<=right){//当等于的时候,也是可以算mid的,必须要考虑这种情况
            if(nums[mid]>target){
                //中间的大,说明目标值在左边,且一定不会是中间值,那么right就是mid-1
                right=mid-1;
                //重新更新mid的值
                //mid=(left+right)/2;
            }else if(nums[mid]<target){
                //中间的小,说明目标值在右边,且一定不会是中间值,那么left就是mid+1
                left=mid+1;
                //重新更新mid的值
                //mid=(left+right)/2;
            }else if(nums[mid]==target){
                return mid;
            }
            mid=(left+right)/2;
        }
        //没有不相等,那就是相等
        //return mid;
        //right<left
        return -1;
    }
}

2.2自己实现过程中遇到哪些困难

遇到不确定while中条件的等于还是不等于,也就是边界处理问题

2.2看完代码随想录之后的想法

避免越界:mid=left+(right-left)>>1;

(right-left)>>1 相当于(left+right)/2

根据左右指针的区间来确定while里面的条件和mid的值

区间一般分为左闭右闭,左闭右开

2.2.1左右指针的区间为左闭右闭时

int left=0;
int right=nums.length-1;
int mid=(left+right)/2;
while(left<=right){
//因为左闭右闭,比如[1,1],用反证法
//左边的1能去到,右边的1也能取到,1=1,那么left=right就是合理的
//反之,左闭右开,比如[1,1)
//左边的1能取到,右边的1不能取到(也就是不为1),那么left=right就是不合理的
	if(nums[mid]>target){
			right=mid-1;//不是right=mid;//因为左闭右闭,明知中间的值是绝对取不到的了
	}else if(nums[mid]<target){
			left=mid+1;
	}else if(nums[mid]==target){
			return mid;
	}
	 mid=(left+right)/2;
}
return -1;

2.2.2左右指针区间为左闭右开时

int left=0;
int right=nums.length;//注意此时不为nums.length-1,因为写这个是能够取到这个值的,我们要开区间,不能取到值
int mid=(left+right)/2;
while(left<right){
//不能相等
//左闭右开,比如[1,1)
//左边的1能取到,右边的1不能取到(也就是不为1),那么left=right就是不合理的
	if(nums[mid>target){
		right=mid;
	}else if(nums[mid]<target){
		left=mid+1;//注意左边能取到,一定不会等于mid值,那就是mid+1
	}else if(nums[mid]==target){
		return mid;
	}
		mid=(left+right)/2;
}
return -1;

3.LeetCode 27.移除元素

题目链接:https://leetcode.cn/problems/remove-element/

3.1自己看到题目的第一想法

思路:暴力解决,第一层for循环查找和目标值相同的元素值,也就是我们用来遍历需要被删除的元素。

如果数组中有元素值等于目标值,进入第二层遍历我们进行对需要删除的元素进行删除操作(数组的删除使用元素覆盖)。

覆盖成功后,我们依旧在此时被删的元素下标处,继续检查一遍,看是否继续等于目标值。

同时,将数组长度-1.

最终返回数组长度

代码:

class Solution {
    public int removeElement(int[] nums, int val) {
        //我们考虑用暴力解决
        //2、每次一遍历,删除掉一个元素(也就是往前覆盖而已),需要重新更新一下数组的长度,是一个变量,要存起来
        //1、遍历一个跟跟目标值相同的元素,我们就移除掉(也就是后面元素向前挪一位,然后继续遍历下去,在删除的这个位置继续),一个移除掉再进行下一个,直到遍历完新的
        int len=nums.length;
        int i=0;
        while(i<len){
            if(nums[i]==val){
                //将i位置后面的所有元素都向前挪一个位置
                for(int j=i;j<len-1;j++){//到倒数第二位
                    nums[j]=nums[j+1];//删除操作
                }
                //为什么这个行,这个就不行,因为得是j+1而不是j++
                //重新去学一下j++和j+1
                //   for(int j=i;j<len-1;j++){//到倒数第二位
                //     nums[j]=nums[j++];//删除操作
                // }
                len--;
            }else{//不相等时,就继续遍历下一个
                i++;
            }
        }
        return len;
    }
}

3.2自己实现过程中遇到哪些困难

为什么用下面这个会报错

for(int j=i;j<len-1;j++){//到倒数第二位
      nums[j]=nums[j++];//删除操作
}

解决1:

for(int j=i;j<len-1;j++){//到倒数第二位
      nums[j]=nums[j+1];//删除操作
}

解决2:

for(int j=i+1;j<len;j++){//到最后一位
	nums[j-1]=nums[j];
}

3.3看完代码随想录之后的想法

思路:双指针思想

一个快指针相当于暴力法的最外层循环,做第一层循环比较每一个元素

一个满指针作为接收nums[fast]≠val的元素,相当于暴力解决的第二层的删除

代码:

class Solution {
    public int removeElement(int[] nums, int val) {
       //双指针,一个作为快指针,用来遍历需要被保留的元素(不被删除)
       //慢指针,用来将不被删除的元素进行存储的指针(相当于一个虚拟的新数组,给每一个下标从0开始进行赋值)
       int fast=0;
       int slow=0;
       for(fast=0;fast<nums.length;fast++){
           if(nums[fast]!=val){
               //将不需要被删除的元素,存储进去数组
               nums[slow]=nums[fast];//存进新数组下标为0的位置开始
               //fast指针在最外层会动了,就不管他
               //此时新数组第一个下标处已有数据,将此时的指针往下进行,也就是
               slow++;
           }
       }
       //当数组中所有的元素都被遍历完了,就出现一个新的数组了,并且新数组的长度为slow
       //这里返回的为什么不是slow++,因为再进行新增加元素后,已经对slow指针往下调了
       return slow;//只需要返回数组长度,不需要返回数组
    }
}

4.今日收获,记录一下自己的成长

今日收获了

1.巩固了数组基础知识,明白了对于数据的访问以及其他操作(增删)是需要根据此数据在内存中的存储方式,按照存储方式对数据进行操作。

2.解决二分查找边界问题,用不同区间来分别解决while条件和mid的值。

3.接触越界处理,避免越界:mid=left+(right-left)>>1;

(right-left)>>1 相当于(left+right)/2

4.对j++,++j,j+1有进一步地了解

5.接触学习了双指针思想和运用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值