算法-代码随想录之 704二分查找、27

131 阅读3分钟

我正在参加「掘金·启航计划」

第一章 数组

数组定义

参考代码随想录的讲解:数组是存放在连续内存空间上的相同类型数据的集合,数组可以很方便的通过下标来获取对应的数据.

有2个注意点

  1. 下标都是从0开始
  2. 数组内存空间的地址都是连续的

因为数组内存空间的地址都是连续的,所以删除或者添加某一项时候,就难免要移动其他元素的地址。数组的元素是不能删的,只能覆盖。

leetcode 704二分查找

这题的前提条件是数组为有序数组,且没有重复项,有重复元素时,找出的下标可能不唯一,这也是使用二分法的前提条件。 已经刷完N次本题,但是都没记住用while循环,还是写文章记下来比较好。首先找到要查找的targer的区间,区间划分一般有两种左闭右闭即[left, right],或者左闭右开即[left, right),区间的定义就是不变量要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

  1. 第一种 左闭右闭[left, right],即target在区间中间,两头都有可能

        /**
         * @param {number[]} nums
         * @param {number} target
         * @return {number}
         */
        var search = function(nums, target) {
            // 首先定义left,right,从0开始,right取length - 1,nums[right]是数组最后一个值,所以right可以闭合
            let left = 0,right = nums.length - 1
            while(left <= right) {
                // 找数组长度的中位数
                const middle = left + ((right-left) / 2) // 防止溢出 等同于(left + right)/2
                if(nums[middle] > targer) {
                    right = middle - 1 // target 在左区间,所以[left, middle - 1]
                } else if(nums[middle] < terget) {
                    left = middle + 1 // target在右区间,所以[middle + 1, right]
                } else {
                    // nums[middle] = target
                    return middle
                }
            }
            // 没有找到目标值
            return -1
        };
    
  2. 左闭右开 [left,right)

    // 代码和上边去吧,主要看区间
    var search = function(nums, target) {
        let left = 0,right = nums.length;
        while(left < right) { // 区别 右边区间是不包含的,所以left < right而不能等于right
            const middle = left + ((right - left) >> 1)
            if(nums[middle] > target) {
                right = middle // 同上,右边不能等于,所以不能减1
            } else if(nums[middle] < target) {
                left = middle + 1
            } else {
                return middle
            }
        }
        return -1
    };
    

leetcode 27移除元素

因为数组的元素是不能删的,只能覆盖。

  1. 解法1 暴力解法 所以如果当前元素和val相等的话,就把后边的一位移过来覆盖掉当前

        /**
          * @param {number[]} nums
          * @param {number} val
          * @return {number}
          */
         var removeElement = function(nums, val) {
             let size = nums.length
             for(let i = 0; i < size; i++) {
                 if(nums[i] === val) {
                     for(let j = i + 1; j < size; j++) {
                         nums[j - 1] = nums[j] // 把后一位的值赋值给前一位
                     }
                     i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                     size--; // 此时数组的大小-1
                 }
             }
             return size
         };
    
    • 时间复杂度:O(n^2)
    • 空间复杂度:O(1)
  2. 解法2 双指针法 双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

    • 快指针:寻找新数组,新数组就是不含有目标元素的数组
    • 慢指针:指向更新 新数组下标的位置
    /**
     * @param {number[]} nums
     * @param {number} val
     * @return {number}
     */
    var removeElement = function(nums, val) {
        let slow = 0
        for(let i = 0; i < nums.length; i++) {
            if(nums[i] !== val) { // 当前不是需要的val的时候,slow才会+1,否则slow就在原地
                nums[slow++] = nums[i]
            }
        }
        return slow
    };
    

代码参照代码随想录