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

704.二分查找

题目链接:https://leetcode.cn/problems/binary-search

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

左闭右闭

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左闭右闭区间
        int left = 0, right = nums.size() - 1;
        while (left <= right){
            int mid = left + (right - left) / 2; //避免溢出
            if(nums[mid] == target) { //直接判断目标值是否存在
                return mid;
            }
            else if(nums[mid] < target){
                left = mid + 1;
            }
            else right = mid -1;
        }
        return -1; 
    }
};

循环不变量:left左边的元素值一定小于target;right右边的元素值一定大于等于target
循环结束时:right < left; 所以left一定大于等于target,判断left与target的关系来确定target是否存在;但是要注意如果升序数组中没有目标值,最后left可能会越界;

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左闭右闭区间
        int left = 0, right = nums.size() - 1;
        while (left <= right){
            int mid = left + (right - left) / 2; //避免溢出
            if(nums[mid] < target){
                left = mid + 1;
            }
            else right = mid -1;
        }
        return left < nums.size() && nums[left] == target ? left : -1; 
    }
};

在这里插入图片描述

左闭右开

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

循环不变量:left左边的元素值一定小于target;right以及right右边的元素值一定大于等于target
循环结束时:right = left; 所以left一定大于等于target,判断left与target的关系来确定target是否存在;但是要注意如果升序数组中没有目标值,最后left可能会越界;

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左闭右开区间
        int left = 0, right = nums.size();
        while (left < right){
            int mid = left + (right - left) / 2; //避免溢出
            if(nums[mid] < target){
                left = mid + 1; //区间更新为[mid+1, right)
            }
            else right = mid;//区间更新为[left, mid)
        }
        return left < nums.size() && (nums[left] == target) ? left : -1; 
    }
};

在这里插入图片描述

27. 移除元素

题目链接:https://leetcode.cn/problems/remove-element/

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
返回 k。
用户评测:
评测机将使用以下代码测试您的解决方案:

int[] nums = […]; // 输入数组
int val = …; // 要移除的值
int[] expectedNums = […]; // 长度正确的预期答案。
// 它以不等于 val 的值排序。
int k = removeElement(nums, val); // 调用你的实现
assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
assert nums[i] == expectedNums[i];
}
如果所有的断言都通过,你的解决方案将会 通过。

示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,,]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,,,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

提示:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

暴力

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        //暴力
        int len = nums.size();
        for(int i = 0; i < len; ++i){
            if(nums[i] == val){
                //所有元素前移 直接覆盖 因为输出不判断后面的值 无所谓
                for(int j = i + 1; j < len; ++j){
                    nums[j - 1] = nums[j];
                }
                --i;//元素前移更新了当前 i 的元素,先 -- 再在循环中 ++ 可以重新判断 nums[i]
                --len;   
            }
        }
        return len;
    }
};

异向双指针

超慢 击败8.92%
在这里插入图片描述
有一点二分的影子在里面

//时间复杂度O(n)
//空间复杂度O(1)
class Solution {
public:
    void swap(int &a, int &b){
        int temp = a;
        a = b;
        b = temp;
    }

    int removeElement(vector<int>& nums, int val) {
        if (nums.size() == 0){ //数组为空,要单独判断,否则会产生下标越界错误
            return 0;
        }
        int i = 0;
        int j = nums.size() - 1;
        //下标 j 右边的元素等于 val, i 左边的元素不等于 val, 中间的元素待判断,左右指针不断缩小区间
        //循环结束时 i = j , 根据 i 左边的元素不等于 val, 最后在判断 nums[i] 和 val 的关系即可;
        //元素总个数为 下标加1;
        while (i < j){
            if (nums[i] == val){
                swap(nums[i], nums[j]);
                --j;
            }
            else {
                ++i;
            }
        }
        if(nums[i] == val){
            return i;
        }
        return i+1;
    }
};
优化后
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int i = 0;
        int j = nums.size() - 1;
        //下标 j 右边的元素等于 val, i 左边的元素不等于 val, 中间的元素待判断,左右指针不断缩小区间
        //循环结束时 i > j , 根据 i 左边的元素不等于 val,
        //元素总个数为 j + 1 = i;
        while (i <= j){
            if (nums[i] == val){
               nums[i] = nums[j]; //直接覆盖重复的元素,更新后的 nums[i] 也要重新判断
                --j;
            }
            else {
                ++i;
            }
        }
        return i;
    }
};

在这里插入图片描述

双指针

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0; 
        int fast = 0;
        while (fast < nums.size()){
            if(nums[fast] != val){    
                nums[slow] = nums[fast];
                ++slow;
            }
            ++fast;
        }
        return slow;
    }
};

这里就是slow表示 不等于val 的数组下标,fast 去遍历原来的数组,如果nums[fast]不等于val,满足条件,就更新到nums[slow],并更新slow;
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值