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

LeetCode 704 二分查找

题目链接:704. 二分查找 - 力扣(LeetCode)

视频链接:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili思路

看到题中说有序数组,还强调无重复元素,那么第一反应就是想想可否用二分法。

而二分法做容易出错的地方就是边界条件,对区间的定义没有搞清楚。通常写二分法时对区间的定义有两种,第一种:[L,R] (左闭右闭)、第二种:[L,R) (左闭右开),也会有极少数人使用左开右闭的写法。

第一种写法:[L,R] (左闭右闭)

首先我们定义一个target在一个左闭右闭的区间里(这里应该知道的是:区间的定义决定了代码的书写),这里应该注意:1、while(L<=R)需使用<=,因为是闭区间,所以L==R是有意义的。2、中间值mid>目标值target时,右边的区间就没了,所以左区间的右边界R就会被赋值为mid-1,因为mid一定不是target

如图所示:

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

代码实现:

class Solution {
public:
    int search(vector& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; 
        while (left <= right) { 
            int mid = (right + left) / 2;
            if (nums[mid] < target) {
                left = mid + 1; 
            }
            else if (nums[mid] > target) {
                right = mid - 1;
            } 
             else { 
                return mid; 
            }
        }
        return -1;
    }
};

 第七行可以这样写:

int mid = left + ((right - left) / 2);//防止溢出 等同于(left + right)/2

·时间复杂度:O(log n)

·空间复杂度:O(1)

第二种写法:[L,R) (左闭右开)

首先我们定义一个target在一个左闭右开的区间里,这里应该注意:1、while(L目标值target时,右边的区间就没了,所以左区间的右边界R就会被赋值为mid,因为mid不等于target

如图所示:

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

!!!注意与第一种写法的区别!!!

代码实现:

class Solution {
public:
    int search(vector& nums, int target) {
        int left = 0;
        int right = nums.size(); 
        while (left < right) { 
            int mid = left + ((right - left) >> 1);// ">>"的意思是右移
            if (nums[mid] > target) {
                right = mid; 
            } 
              else if (nums[mid] < target) {
                left = mid + 1; 
            } 
              else { 
                return mid;
            }
        }
        return -1;
    }
};

·时间复杂度:O(log n)

·空间复杂度:O(1)

收获

明白了二分法容易出错的地方,对二分法有了更深刻的理解。

LeetCode 27 移除元素

题目链接:27. 移除元素 - 力扣(LeetCode)

视频链接:数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili

思路

前提要知道数组的元素在内存地址中是连续的,不能单独删除某个元素,只能覆盖。

第一种解法:(暴力解法)

暴力解法:就是使用两层for循环,一个负责遍历数组元素,一个负责更新数组

代码实现:

class Solution {
public:
    int removeElement(vector& nums, int val) {
        int size = nums.size();
        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;

    }
};

·时间复杂度:O(n^2)

·空间复杂度:O(1)

第二种解法:(双指针法)

双指针法:通过两个指针(一个块指针,一个慢指针)在一个for循环下完成两个for循环的工作

这里最容易懵圈的地方就是对快慢指针的含义。

快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组 

慢指针:指向更新 新数组下标的位置

代码实现:

class Solution {
public:
    int removeElement(vector& nums, int val) {
    int slowIndex = 0;
    for(int fastIndex = 0;fastIndex < nums.size();fastIndex++){
        if(nums[fastIndex] != val) {
            nums[slowIndex] = nums[fastIndex];
            slowIndex++;
        }
    }
    return slowIndex;
    }
};

·时间复杂度O(n)

·空间复杂度O(1)

收获

对快慢指针的含义更清晰了

你可能感兴趣的:(算法,c++)