数组部分:双指针还是有点细节上面的问题

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

数组部分

题目描述 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

首先描述二分查找,二分查找就是将一段数据一分为二,然后判断目标值在哪一个段内,剩下的一段区间就不需要再判断了

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

因为是之前的做过的题目,所以代码写的还挺快的,但是这次想试一下符号右移1位的方法来实现,结果显示时间超时

27.给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

基本思路:
遍历数组,如果遇到数值等于val的话,让后面的数据往前移,注意需要使用一个变量用来保存数组的新长度(直接让后面的元素往后面移动的话,感觉有点麻烦,想不出来该怎么做,换一种方法,将元素等于value值的元素放在数组的最后面,这样的话其实就是双指针了,暴力的方法是什么样的呢)

public int removeElement(int[] nums, int val) {
        int left=0,numL=nums.length,right=numL-1;
       for(int i=0;i<numL;i++){
           int temp=0;
           //左指针表示新数组的长度,右指针表示从该位置开始,后面的位置中存储的都是value
           if(nums[i]==val){
               nums[i]=nums[right];
               nums[right]=val;
               right--;
           }else{
               left++;
           }
       }
       return left;
    }

这样写的话出现了问题,就是当right指向的元素刚好是value时,就会出现不能移除所有的value的问题,因为把最后的value的移动到了前面,这是一个需要解决的问题
写出来了,但是感觉小问题不断

public int removeElement(int[] nums, int val) {
        int left=0,numL=nums.length,right=numL-1;
       for(int i=0;i<=right;i++){
       //while中添加一个判断 即如果right位置处的值是value的话,就right向前移
       //这边的小细节还是挺多的,即right往前移的时候需要保证是有效的
           while( right>=0 && nums[right]==val){
               right--;//是对最右边指针是否位value的判断
               if(right<0){
                   return 0;//如果数组中只有一个元素且元素的值是value的话,直接结束
               }
               if(i>right){
                return left;//另一个方面,需要保证被判断的值是要小于右边的边界的,否则直接返回
               }
           }
           int temp=0;
           if(nums[i]==val && i<=right){
               nums[i]=nums[right];
               nums[right]=val;
               right--;
           }
               left++;
       }
       return left;
    }

看一下答案的逻辑
暴力解法,就是之前提到过的,如果元素的值为value的话,将该元素放到最后面,然后所有的元素向前移动,使用双层for循环来解决这个问题(实现一下)
暴力解法需要注意的点,需要对第一层循环进行更新,否则的话会超出时间限制,也会数组越界
并且另外一个需要注意的点是,在把该位置后面所有的数据往前移动之后,第一层循环的i值需要回退一个,因为该位置上是更新过后的数组,不能确保它的值是否为value
另外发现,如果想不通逻辑的话,去debug,不要浪费时间,因为真的是很难想的出来

 public int removeElement(int[] nums, int val) {
        int num=0;//表示value值的个数
        for(int i=0;i<nums.length-num;i++){
            if(nums[i]==val){
                num++;
                for(int j=i;j<nums.length-num;j++){
                    nums[j]=nums[j+1];
                }
                i--;//自己写出来的 开心
            }
        }
        return nums.length-num;
    }

双指针的解法
答案里面的思路用的是快慢指针,我觉得比我想得那个左右指针更容易想一点,边边角角的小细节可能更少一点
这边的小细节确实比左右指针少多了
但是需要注意的是,对于fast=slow的判断要放在fast>slow的前面,因为如果>的话,就会去做对应的操作,刚好把fast=slow的条件满足了,所以这边存在一个判断的顺序问题

 public int removeElement(int[] nums, int val) {
        int fast=0,slow=0;
        while(fast<nums.length){
            if(nums[fast]!=val && fast==slow){
                slow++;
            }
            if(nums[fast]!=val && fast>slow){
                nums[slow]=nums[fast];
                slow++;
            
            }
            fast++;
        }
        return slow;
    }

总结:

  1. 27题:使用左右指针实现数组的指定元素的删除操作,小细节过多,快慢指针更简单一点,但是同样需要考虑判断的顺序问题 704题这边对于右开还是右闭没做过多的讨论,现在只是想快一点的把题刷完
  2. 针对右移一位的问题,当元素是非负数值时,/2与右移1位的效果一样,当元素为负数且为偶数时,结果也是一样,只能保证这两种结果一样
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值