代码随想录训练营day01记录: 二分查找, 移除元素双指针

训练营的第一天, 上个月开始决定转码,马虎的学习了java的一些基础知识,看了几集韩顺平,赶感觉有本质上的提升,于是开始正式刷题. 第一天感觉还行, 虽然直接做题做不出来,但是看解法还是看得懂的,一定要坚持接下来两个月

今天的第一题是关于二分查找,binary search,前提是有序且不重复的

左闭右闭 和 左闭右开

两种解法,在一开始的index, while循环条件,和边界上皆有不同

首先介绍我写的左闭右闭:

看完carl哥的视频后还是比较理解的,但是上手写的时候有很多bug:

1.分清楚写的是数字还是index,这里的target, left和right是不同含义

2.分清楚条件,一开始就要判断target的合理性

3.右闭的话,判断条件就是小于等于

4. 在while循环判断是已经包括了middle(right),所以此时的middle已经不在新的区间里了,应该用middle-1/+1

5.>>是向右位移, 直接用left + (right - left)/2 一样(是为了防止数字过大超过边界)

6.这里有四种情况,大于,小于,等于(相当于直接找到了),遍历完都没有

class Solution {
    public int search(int[] nums, int target) {
        //左闭右闭
        if(target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }

        int left = 0;
        int right = nums.length - 1; //这里由于右边闭合了

        while(left <= right) {
            int middle = left + ((right - left)>>1); //这里可以进一步了解
            if(nums[middle] > target) {
                right = middle -1; 
            } else if(nums[middle] < target){
                left = middle +1;
            } else if(nums[middle] == target){
                return middle;
                }
        }
        return -1;
    }
}

接下来是左闭右开:
在这里犯了几个低级错误

1.忘记给写 int middle = xxx了,记住java永远是面对对象的

2.记住对middle的赋值要放在循环里,不然是不会改变的

3.这里区别就是,right的定义就是num.size; left一样,但是right 直接=middle

class Solution {
    public int search(int[] nums, int target) {
        //左闭右开
        if(target < nums[0] || target > nums[nums.length - 1]){
            return -1;
        }

        int left = 0;
        int right = nums.length;  //这里右边是开的,所以直接num.length
        while (left < right) {
            int middle = left + (right - left)/2;
            if(nums[middle] < target) {
                left = middle + 1;
            } else if (nums[middle] > target) {
                right = middle;
            } else if (nums[middle] ==  target) {
                return middle;
            }
            
        }
        return -1;
    }
}

下一个是移除元素,有暴力解法和双指针解法

暴力解法:

这个对我来说反而不好理解,反正就是有两个for,第一个是来遍历每一个元素来匹配val;第二个是找到val后,将后面的元素覆盖到前面;

注意条件:
1. 判断如果找到val,进入遍历循环,新的数j, j=i+1,意思是val后面那个元素是j

2. 通过nums[j-1]=nums[j]来覆盖值,然后i--(后面的元素集体往前挪了,所以要减一复原),size--;

class Solution {
    public int removeElement(int[] nums, int val) {
        int size = nums.length;
        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;

    }
}

双指针解法:

一个快指针:寻找新数组里所需要的元素(不含target的),也是index

一个慢指针:新数组的下标值就是slow

有以下注意事项:

1. 快指针无论什么情况都+1,慢指针符合条件才+1

2. 当快指针不等于target时,才是我们要的新数组元素

3.if里面要给slow代表的新数组赋值,也要给slow指针右移

4.这里如果不是if,slow就不会移动,也不会给新数组赋值,所以相当于删除了

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        for(int fast = 0; fast < nums.length; fast++){
            if(nums[fast] != val){
                nums[slow] = nums[fast];   //这里要理解好,是给slow代表的新数组赋值
                slow++;                    //同时慢指针要向右移动         
            }
        }
        return slow;

    }
}

注意:这里总是会有sb小错误,比如nums总是写成num,甚至分号都忘记打。

你可能感兴趣的:(算法,leetcode,数据结构)