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

力扣704.二分查找

题目链接

视频讲解

主要思路:

1 定好左端点与右端点

2 比较由左端点与右端点得出的中间值与目标值关系,根据此关系修改左端点或右端点,得出新的中间值,重复上述过程

易错点:

1 区间的关系:如果是全闭区间,则在while中应该是left<=right,因为[1,1]是合法区间,

而如果是左闭右开区间,则在while中应该是left

2 左右端点的修改:如果是全闭区间,修改左端点则是middle+1,修改右端点则是middle-1,因为已知middle不符合要求,则要在新区间中排除

而如果是左开右闭区间,左端点修改是middle+1,右端点修改是middle,因为右端点本来就不包含在合法区间里

全闭区间代码实现:

int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize - 1;    //小技巧,用下标值,不用定义指针,与出入的数组首地址组成指针
    int ret = -1;
    while(left <= right) {                //易错一
        int middle = (right + left) / 2;
        if(nums[middle] < target) {
            //printf("%d\n",nums[middle]);
            left = middle + 1;            //易错二
        }
        else if(nums[middle] > target) {
            //printf("%d\n",nums[middle]);
            right = middle - 1;
        }
        else {
            //printf("%d\n",ret);
            ret = middle;
            break;                
        }
    }
    return ret;
}

左开右闭区间代码实现 

int search(int* nums, int numsSize, int target){
    int left = 0, right = numsSize;
    int ret = -1;
    while(left < right) {        //易错一
        int middle = (left + right) / 2;
        if(nums[middle] < target) {
            left = middle + 1;    
        }
        else if(nums[middle] > target) {
            right = middle;    //易错二
        }
        else {
            ret = middle;
            break;
        }
    }
    return ret;
}

第一次写错误 

查找到目标值后忘break了,陷入死循环

补充

二分法适用于已排序好且无重复元素的数组

力扣27 移除元素

题目链接

视频讲解

主要思路

首先数组中元素是无法真正移除,只能靠后一个元素覆盖前一个元素

1 暴力 时间复杂苏O(n^2)

第一个循环遍历原数组,发现目标后再进行一次循环,从当前位置将后面的元素向前移动一位

易错点

1 数组的大小在每次找到一个目标值后要减1

2 里层循环的限制条件要避免下标溢出

3 为了防止目标值后面恰好又是目标值,移动后外层循环下标暂不移动

暴力代码实现

int removeElement(int* nums, int numsSize, int val){
    int size = numsSize;    
    for(int i = 0; i < size; i++) {
        if(nums[i] == val) {
            for(int j = i; j < size - 1; j++) {    //j < size-1这样最后止步于数组里倒数第二位与最后一位比较,如果是j < size那j = size时j + 1就溢出了
                nums[j] = nums[j + 1];
            }
            size--;    
            i--;     //这步很关键,是为了防止移动后外层循环的位置上恰好又是目标值
        }
    }
    // for(int i = 0; i < size; i++)
    //     printf("%d ",nums[i]);
    // putchar('\n');
    return size;
}

第一次错误:

1 没有在每次找到目标值后修改size

2 忽略了移动后原位置还可能是目标值

2 快慢指针  时间复杂度O(n)

(1)定义一个快指针用于遍历“旧”数组

(2)定义一个慢指针用于创建“新”数组

代码实现

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

算法训练营额外收获

1 左移一位相当于除以2,右移一位相当于乘以2

比如1111是15,右移一位变成111就是7,相当于15/2

你可能感兴趣的:(算法训练营,算法)