【每日算法】

算法第1天|704 二分查找、27 去除元素

*简介:记录一刷算法存在的问题和解题思想,养成每日学习总结的习惯
704:二分查找
题目链接

提示:由于数组元素有序且可以假定不重复,因此想到使用二分查找;
二分查找的关键:

  1. 能想到用二分查找来解决;
  2. 根据区间的定义确定判断条件是否需要等号,新的区间是否要+1 or -1.(闭1)
/*
存在的问题:
1.循环的结束条件
2.没有考虑左闭右闭or左闭右开
3.left right的初始化
4.未考虑left+right可能会溢出的问题
*/
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int middle = nums.size()/2
        while(){
            if(traget < right)
            right = middle;
        else if (target > left)
            left = middle;
        else
            return middle;
        }
        return -1;
    }
};

正解
左闭右闭:

/*用时3ms*/
1.循环的结束条件:即二分查找条件,查找范围不为空
2.溢出问题:若数组长度较大,计算中点操作(left+right)/2 中的left+right可能超出int类型的取值范围,从而导致计算错误。此时,需使用(right-left)/2+left计算中点,避免此问题。
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size()-1; //左闭右闭
        while(left <= right){
            int middle = left + ((right - left)/2);
            if (target < nums[middle]){
                right = middle - 1;
            } else if (nums[middle] < target) {
                left = middle + 1;
            } else {
                return middle;
            }    
        }
        return -1; 
    }
};

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

左闭右开

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size(); //左闭右开时,right初始化为size,不减一!!!
        // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
        while(left < right){ //左闭右开,当left=right时循环就停止;
            int mid = (right - left) / 2 + left; //防溢出
            int num = nums[mid];
            if (num == target) { //先处理最简单的情况
                return mid;
            } else if (num > target) {
                right = mid;
            } else {
                left = mid+1;
            }
        }
        return -1;
    }
};
时间复杂度:O(log n)
空间复杂度:O(1)

相关题目推荐 后面抽时间or二刷做

27:去除元素
题目链接

方法:暴力解法、双值针法(快慢指针)、双指针优化(左右指针)

/*暴力解法*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int num = nums.size();
        for (int i=0; i<num; ++i) {
            if (val == nums[i]) {
                for (int j=i+1; j<num; j++) {
                    nums[j-1]=nums[j]; //数组整体左移一位
                }
                i--;
                num--;//下标和数组长度减少1
            }
        }
        return num;
    }
};
/*双指针法*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0, size = nums.size();
        //快慢指针,各遍历一次
        for (int fast = 0; fast < size; fast++) {
            if (nums[fast] != val) {
                nums[slow++] = nums[fast];
            }
        }
    return slow;
    }
};

复杂度分析:
时间复杂度:O(n),其中 n为序列的长度。只需遍历该序列至多两次,两个指针各一次。
空间复杂度:O(1),只需常数空间保存若干变量。

/*双指针优化*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int left = 0, right = nums.size();
        //头尾指针,共同遍历一次
        while (left < right) {
            if (nums[left] == val) {
                nums[left] = nums[right - 1];
                right--;
            } else {
                left++;
            }
        }
        return left;
    }
};

复杂度分析:
时间复杂度:O(n),其中 n为序列的长度。只需遍历该序列至多一次(两个指针在最坏的情况下合起来只遍历了数组一次。双指针优化方法避免了需要保留的元素的重复赋值操作。)。
空间复杂度:O(1),只需常数空间保存若干变量。
相关题目推荐 后面抽时间or二刷做

参考链接:
作者:力扣官方题解、Krahets
链接:https://leetcode.cn/problems/binary-search/solutions/980494/er-fen-cha-zhao-by-leetcode-solution-f0xw/
https://leetcode.cn/problems/binary-search/solutions/1/by-jyd-i7xr/
https://leetcode.cn/problems/remove-element/solutions/730203/yi-chu-yuan-su-by-leetcode-solution-svxi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值