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

668 阅读2分钟

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

704.二分查找

代码随想录 (programmercarl.com)

自己看到题目的第一想法

看到题目的第一想法就是使用循环,一个一个的遍历,直到找到target或者遍历完。

但是看到题目中的n个元素有序,并且所有元素不重复,这种明显可以用二分法来降低复杂度。

下面是自己调试后写出的代码:

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

看完代码随想录之后的想法

代码随想录中二分法有两种写法,一种是target是在一个在左闭右闭的区间里,这种时候就像上面的代码,判断时left<=right,同时left = mid + 1right = mid - 1

另一种是target 是在一个在左闭右开的区间里,这时候判断循环left<right,同时left = midright = mid

比较值得注意的一点是如果为左闭右开的区间len应该为nums.length而不需要减一了。

二分法对区间的定义很重要,如果不清楚很容易搭配错误。

对于

mid = left + ((right - left) >> 1);

1010>>1 === 0101 十进制由10->5,所以>>1就相当于除以二。为了防止left+right超过基本类型所能容纳的最大值,所以使用位运算,而且位运算更快一些。

自己实现过程中遇到哪些困难

对于right = nums.length - 1,一开始忘记减一,排查了一会。

27.移除元素

数组作为一种连续存储的结构,并不能简单的删除某个位置的元素,只能进行覆盖操作。

自己看到题目的第一想法

暴力解法:如果遇到val就用后面的覆盖val,数组长度减一。

var removeElement = function(nums, val) {
    let len = nums.length
    for(let i = 0;i < len;i++) {
        if(nums[i] === val) {
            for(let j = i + 1;j < len;j++) {
                nums[j - 1] = nums[j]
            }
            i--
            len--
        }
    }
    return len
};

这种解法时间复杂度很高,为n的平方。

看完代码随想录之后的想法

使用双指针的方式,可以使用一个for循环完成两个for循环的工作。如果遇到目标数,慢指针不加一,可以将非目标数替换到前面的位置。

快指针用来指向新数组所需要的元素,也就是非target的元素。慢指针是新数组的长度。

var removeElement = function(nums, val) {
    let k = 0
    for(let i = 0;i < nums.length;i++) {
        if(nums[i] != val) {
            nums[k++] = nums[i]
        }
    } 
    return k
};

今日收获,记录一下自己的学习时长

今天的题比较简单,花了两个小时做题+写博客。

今天复习了二分法的使用、位运算的使用以及双指针的使用。