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

85 阅读2分钟

704.二分查找

题目链接:leetcode.cn/problems/bi…

第一想法

暴力解法,直接遍历整个数组

思路

利用二分法,一步一步缩小搜索区间,注意边界的选取与终止条件的设置

1.[left,right]

  • 循环条件设置为while(left < = right)

    因为区间是左闭右闭的,所以left = right时有意义,即最终终止条件为left 在 right的右边

  • if(nums[mid] > target) ,right = mid - 1

    if(nums[mid < target]), left = mid + 1

JS实现代码如下:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = 0, right = nums.length - 1, mid = 0;
    while(left <= right){
        mid = left + parseInt((right - left)/2 );
        if(nums[mid] > target){
            right = mid - 1;
        }else if(nums[mid] < target){
            left = mid + 1;
        }else{
            return mid;
        }
    }
    return -1;
};

2.[left,right)

  • 初始条件right = nums.length,这里不需要减1

  • 循环条件设置为while(left < right)

    因为区间是左闭右开的,所以left = right 已经到终止条件了

  • if(nums[mid] > target) ,right = mid

    if(nums[mid < target]), left = mid + 1

    因为左边是闭区间,所以left 还是要+1

JS代码如下:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let left = 0, right = nums.length, mid = 0;
    while(left < right){
        mid = left + parseInt((right - left)/2 );
        if(nums[mid] > target){
            right = mid;
        }else if(nums[mid] < target){
            left = mid + 1;
        }else{
            return mid;
        }
    }
    return -1;
};

总结

使用二分法后,算法的时间复杂度从O(N)降低到了O(log2N)

两种方法掌握一种就可以,因为这类题目还有许多变式,所以以后打算统一使用第一种方法

二分法最重要的地方在于边界的选取以及想明白终止条件是什么,容易出现细节上的失误

因为这道题前不久刚学,所以今天做的比较顺畅

27.移除元素

题目链接:leetcode.cn/problems/re…

第一想法

数组的插入和删除比较复杂,需要按顺序逐个移动元素。用暴力解法的话,可以遍历一遍数组,对于满足条件的元素,把该元素后面的元素依次往前移一个位置,这样需要使用2个for循环

暴力解法:

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    let i = 0, j= nums.length,k = 0,count = 0;
    for(i=0; i<j; i++){
        if(nums[i] == val){
            for(k=i; k<j-1; k++){
                nums[k] = nums[k+1]
            }
            nums[k] = 0;
            count++;
            i = i-1;  // 因为数组位置移动了,所以这里必须i - 1          
        }
    }
    j = j - count;
    return j;
};

这题的暴力解法超出时间限制了

思路

双指针法:

利用一个快指针,一个慢指针

当数组的值不等于val时,快慢指针同时+1

如果值等于val,则快指针+1,慢指针不动,即跳过了这个数

最后把慢指针的值返回

相当于用后面的元素把等于val的元素覆盖掉了

JS 代码如下:

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    let slow = 0,fast = 0;
    for(fast=0; fast < nums.length; fast++){
        if(nums[fast] !== val){
            nums[slow++] = nums[fast];
        }
    }
    return slow;
};

总结

双指针法这个思路很重要,需要记住

对于数组这种不方便插入和删除的结构来说,用双指针法对其进行处理会方便许多

今日总结

因为这两道题半个月前学过,所以今天写的比较顺利,做题+写博客一共64分钟

其实二分法也可以视为双指针法,只是指针是相向而行的

双指针的思想还是挺重要的