DAY1 打卡:第一章 数组part01

57 阅读2分钟
704. 二分查找

二分查找精髓:循环不变量

大家解释是:要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

我的理解是:每一次循环维持目标值在定义的区间中,这个动作看成不变量。

// 左闭右闭原则

        while (left<=right){
            int i = (left + right) / 2;
            if (nums[i] > target){
                right = i-1 ;
            }else if (nums[i] < target){
                left = i+1 ;
            }else{
                return i;
            }
        }

// 左闭右开原则

    while (left<right){
            int i = (left + right) / 2;
            if (nums[i] > target){
                right = i ;
            }else if (nums[i] < target){
                left = i+1 ;
            }else{
                return i;
            }
        }
27. 移除元素

// 暴力法

emmm暴力法我没能写出来,值得借鉴:

  1. size控制遍历数组长度,防止死循环
  2. nums[j-1] = nums[j],不考虑遍历最后一位元素

没能写出原因:逻辑思维有点混乱,边界值考虑不全,没有对数组遍历长度进行控制,导致死循环。

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;
    }

// 双指针

暴力法,对于每一个等于 val 的元素,你都将数组后面的元素向前移动一位。这个过程的时间复杂度是 O(n2),因为对每个找到的元素,需要移动其后的所有元素。当数组很大时,这将非常低效。

借用卡哥的话,使用快慢指针的本质是理解快慢的含义

public int removeElement(int[] nums, int val) {
        int slow =0;
        for (int quick=0; quick<nums.length; quick++){
            if (nums[quick] != val){
                nums[slow++] = nums[quick];
            }
            
        }
        return slow;
    }

nums[slow++] = nums[quick]; 还是很巧妙的,使用了后++运算符特性。

后感: 本以为二分法、双指针以及暴力法能够轻松解决,实际写起来还是有诸多问题(边界值)甚至是没有想到思路。目前对此还是有点疑惑感的,需要多周目。