随想录训练营Day1|704.二分查找、27.去除元素

1,015 阅读3分钟

随想录训练营Day1|704.二分查找、27.去除元素

标签: LeetCode闯关记


1. 704.二分查找 1.1 题目 相关链接 704 二分查找

参考labuladong: 双指针技巧秒杀七道数组题目 ###1.2 解题思路 二分查找 ###1.3 遇到问题 无 ###1.4 算法实现 算法分析

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

            }else if( nums[mid] < target){
                left = mid + 1;
            }
        }
        return -1;

    }
}

注意点:待更新

###1.5 题目总结 解题耗时:30min ###1.6 相关题目

  1. 35. 搜索插入位置: 左侧边界
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        
        while(left <= right){//查找范围:[left,right] = [0, nums.length - 1](左闭右闭)
        int mid = left + (right - left)/2; //注意
           if(nums[mid] > target){
               right = mid - 1;
           }else if (nums[mid] < target){
               left = mid + 1; 
           }else if (nums[mid] == target ){
               right = mid - 1;//target已经找到后, 令right = mid - 1, 所以对于nums[mid]恒< target,left不断变为mid-1,即left不断右移,until left第一次>right, 此时, 即left - 1 = right,因不满足while循环条件而退出循环.这时的left指向的元素就是target,因为 left - 1 = right,且 right = mid - 1, mid 为target,则nums[left] = target;
           }
        }
        return left;
    }
}
  1. 34. 在排序数组中查找元素的第一个和最后一个位置: 左右侧边界
class Solution {
    public int[] searchRange(int[] nums, int target) {
     return new int []{left_bound(nums, target), right_bound(nums, target)};
    }
    //寻找左侧边界
    int left_bound(int[]nums, int target){ 
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] >= target){
                right = mid - 1;
            }else if(nums[mid] < target){
                left = mid + 1;
            }
        } 

        //判断边界
        if(left > nums.length - 1 || nums[left] != target){ 
            return -1;
        }else{ return left;}
    }

    //寻找右侧边界
     int right_bound(int[]nums, int target){
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] > target){
                right = mid - 1;
            }else if(nums[mid] <= target){
                left = mid + 1;
            }
        }

        //判断边界
        if( right < 0 || nums[right] != target){ 
            return -1;
        }else{ return right;}
    }
}

##2. 27.去除元素 ###2.1 题目 题目:原地移除=val的元素 ###2.2 解题思路 1.暴力求解 2.快慢指针 ###2.3 遇到问题 报错: 时间超过限制(法1) 原因:for循环的循环条件---- i < new_length 写成 i< nums.length

报错:越界异常(法2) 原因: slow++ 写在 nums[slow] = nums[fast]之前 ###2.4 实现代码 1.两次for循环 算法实现:

class Solution {
    public int removeElement(int[] nums, int val) {
        //遍历数组,遍历到删除元素后,将其删除
        int new_length = nums.length;
        for(int i = 0; i < new_length; i++){//错把i < new_length写成了i < nums.length,导致时间超出限制
            if(nums[i] == val){
                for( int j = i + 1; j < new_length; j++){//错把j < new_length写成了j < nums.length,导致时间超出限制
                    nums[j - 1] = nums[j];
                }
                nums[nums.length - 1] = 0;
                i--;//因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                new_length--;//// 此时数组的大小-1
            }   
        }
        return new_length;
    }
}

注意点: i--: 作用是为了避免遍历过程中漏掉重复的 val 元素。因为删除一个元素后,后面的元素会向前移动一位,而当前的 i 指向的是被删除的元素的下一个元素,因此需要将 i 向前移动一位,继续判断当前位置的元素是否为 val,直到找到下一个非 val 元素。

2.快慢指针

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0, fast = 0;
        while(fast < nums.length){
            if(nums[fast] != val){     
            nums[slow] = nums[fast];
            slow++;//注意slow++ 和 nums[slow] = nums[fast] 的位置关系
            }
            fast++;
         }
        return slow;
    }
}

注意点: 注意slow++ 和 nums[slow] = nums[fast] 的位置关系:例如,

假设在第一个元素上有要删除的值 val,那么如果在将 nums[slow] 赋值之前执行 slow++,则第一个元素将永远不会被覆盖,并且如果没有其他不等于 val 的元素,将返回错误的长度。

此外,如果 slow++ 放在 nums[slow] = nums[fast] 之后,将可能导致 slow 超过数组的长度并导致数组越界异常。因为当 fast 遍历数组时,slow 被赋值为所有非 val 元素的索引,这意味着 slow 可能超过最后一个非 val 元素的索引,而这个索引的最大值是 nums.length - 1。

###2.5 题目总结 解题耗时: 40min ###2.6 相关题目 1.26. 删除有序数组中的重复项 快慢指针:

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length == 0){
            return 0;
        }
       int low = 0;
       int fast = 0;
       while (fast < nums.length){
           if(nums[low] != nums[fast]){
               low++;
               nums[low] = nums[fast];
           }
           fast++;
       }
       return low + 1;//注意:需要+1,返回数组长度

    }
}

2.283. 移动零

class Solution {
    public void moveZeroes(int[] nums) {
        int slow = 0;
        int fast = 0;
        while(fast < nums.length){
        if(nums[fast] != 0){
            nums[low] = nums[fast];
            slow++;//注意
        }
        fast++;
        } 
        return slow;
        for(int p = slow; p < nums.length; p++){
            nums[p] = 0;
        } 
    }
}

##3. 今日心得 写博客好累,以及第一次转码人刷题确实漏洞百出,千疮百孔. 得下个编译器,markdown用得还不太顺畅. Thanks for ChatGPT's help!