算法训练01 | 数组part01_数组理论基础、704. 二分查找、27. 移除元素

参考文章

算法记录 | Day1数组基础 - 掘金

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

今日任务

第一章 数组part01

数组理论基础,704. 二分查找,27. 移除元素

详细内容:  

 数组理论基础  

文章链接:代码随想录

题目建议: 了解一下数组基础,以及数组的内存空间地址,数组也没那么简单;

 704. 二分查找 

题目建议: 大家能把 704 掌握就可以,35.搜索插入位置 和 34. 在排序数组中查找元素的第一个和最后一个位置 ,如果有时间就去看一下,没时间可以先不看,二刷的时候在看。

先把 704写熟练,要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

文章讲解:代码随想录

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

前提条件

  • 有序数组
  • 数组中无重复元素

middle的选取

参考文章:算法记录 | Day1数组基础 - 掘金

  • mid = (right + left) // 2这种写法会发生上溢问题。int 占用 4 字节,32 比特,数据范围为:-2147483648 ~ 2147483647 [-2^31 ~ 2^31-1]

    那么对于两个都接近 2147483647的数字而言,它们相加的结果将会溢出,变成负数。所以,为了避免溢出情况的发生,我们不采用这种写法。

  • mid = left + (right - left) // 2 从左指针到右指针的一半距离 + 左指针的下标 才是符合题的下标位置。

代码

左闭右闭的区间
#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;                  // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) {                       // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2); // 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else {               // nums[middle] == target
                return middle;     // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

int main() {
    vector<int> nums = {-1, 0, 3, 5, 9, 12};
    int target = 9;
    Solution solution;
    cout << solution.search(nums, target) << endl;

    cin.get();
    return 0;
}
左闭右开的区间
#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) {   // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else {               // nums[middle] == target
                return middle;     // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

int main() {
    vector<int> nums = {-1, 0, 3, 5, 9, 12};
    int target = 9;
    Solution solution;
    cout << solution.search(nums, target) << endl;

    cin.get();
    return 0;
}

27. 移除元素

题目建议:  暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍。 双指针法 是本题的精髓,今日需要掌握,至于拓展题目可以先不看。 

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

文章讲解:代码随想录

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

双指针

  • 快指针先移动,如果不是目标元素,快指针指向就赋值给慢指针指向,慢指针移动

  • 如果是目标元素,则慢指针不操作,快指针继续移动。

  • 慢指针最后指向的下标,就是新数组中的大小

代码

暴力解法
#include <iostream>
#include <vector>
using namespace std;

// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& 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--;    // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;
    }
};

int main() {
    vector<int> nums = {0, 1, 2, 2, 3, 0, 4, 2};
    int val = 2;
    Solution solution;
    int newSize = solution.removeElement(nums, val);

    // 输出修改后的 nums 数组
    cout << "Modified nums array: ";
    for (int i = 0; i < newSize; i++) {
        cout << nums[i] << " ";
    }
    cout << endl;

    // 输出修改后的数组大小
    cout << "New size of nums: " << newSize << endl;

    cin.get();
    return 0;
}
双指针
#include <iostream>
#include <vector>
using namespace std;

// 时间复杂度:O(n)
// 空间复杂度:O(1)
// 双指针方法
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

int main() {
    vector<int> nums = {0, 1, 2, 2, 3, 0, 4, 2};
    int val = 2;
    Solution solution;
    int newSize = solution.removeElement(nums, val);

    // 输出修改后的数组大小
    cout << "New size of nums: " << newSize << endl;

    // 输出修改后的 nums 数组
    cout << "Modified nums array: ";
    for (int i = 0; i < newSize; i++) {
        cout << nums[i] << " ";
    }
    cout << endl;

    cin.get();
    return 0;
}

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值