代码随想录算法训练营第一天|704. 二分查找,27. 移除元素,34. 在排序数组中查找元素的第一个和最后一个位置,35. 搜索插入位置

数组基础理论

数组是存放在连续内存空间上的相同类型数据的集合。

删除或增添元素时,要移动其他元素的地址。

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

vector是容器,不是数组。

二维数组在内存的空间地址是连续的么?c++是,java不是。

704. 二分查找

思路:最基本的二分查找,略。

时间复杂度:O(logn)

空间复杂度:O(1)

注意:

1.我习惯左闭右闭的写法,判断条件是while(left<=right)。

2.按照target的位置来找。

3.二分查找使用的条件:数组有序,元素唯一

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

27. 移除元素

思路:暴力解法,两层for循环,外层用于遍历整个数组,内层用于移动剩余元素。

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

空间复杂度:O(1)

注意:

1.预先定义一个size,可以动态变化数组的实际大小。

2.覆盖操作的时候,注意左右边界,不要访问数组越界。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int i = 0;
        //预先定义一个size,可以动态变化数组的实际大小
        int size = nums.size();
        while(i < size){
            if(nums[i] == val){
                for(int j = i; j  < size - 1; j++){
                    nums[j] = nums[j + 1]; 
                }
                size--;
            }
            else{
                i++;
            }
        }
        return size;
    }
};

思路:前后指针,前指针维护已经确定的结果数组的右边界,后指针向前遍历寻找符合条件的元素,如果找到了,就将后指针指向的元素覆盖前指针指向的元素,前指针+1。

时间复杂:O(n)

空间复杂度:O(1)

注意:

1.左闭右闭

2.向前找

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int front = 0;
        int rear = nums.size() - 1;
        //左闭右闭
        while(front <= rear){
            if(nums[front] == val){
                nums[front] = nums[rear];
                rear--;
            }
            else{
                front++;
            }
        }
        return front;
    }
};

 

思路:双指针:快慢指针,慢指针维护已经确定的结果数组的右边界,快指针向前遍历寻找符合条件的元素,如果找到了,就将快指针指向的元素覆盖慢指针指向的元素,慢指针+1。(和前后指针一样,只不过一个是向后找,一个是向前找)

时间复杂度:O(n)

空间复杂度:O(1)

注意:

1.左闭右闭

2.向后找

3.这个方法代码最简洁

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        //fast在nums中去找与val不同的元素
        //slow维护找到的元素的右边界(开区间),因此实际的找到的元素数量=slow
        int fast = 0;
        int slow = 0;
        for(;fast<nums.size();fast++){
            if(nums[fast] != val){
                nums[slow++] = nums[fast];
            }
        }
        return slow ;
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

思路:二分查找的应用,一个二分查找可以找到一个元素的位置,因此要找到第一个和最后一个位置,需要使用两次二分查找。

时间复杂度:O(logn)

空间复杂度:O(1)

注意:

1.二分查找要求:数组有序,元素唯一;而本题条件:数组有序,元素不唯一。 

2.代码可以分块写,思路更清晰。也可以优化一起写,代码更简洁。

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

35. 搜索插入位置

思路:二分查找的应用,在二分查找的基础上,考虑找不到的处理情况

时间复杂度:O(logn)

空间复杂度:O(1)

注意:

1.二分查找要求:数组有序,元素唯一,本题完美符合。

2.未找到是的插入位置可以有两种:return right + 1;或者 return left;(注意不是left + 1

3.未找到情况下,循环结束时,left和right指针的位置情况:

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值