DAY 1!二分查找与快慢指针

文章目录

  • 题目:704. 二分查找
    • 实现算法:二分法
    • 做题心得
  • 27. 移除元素
    • 双指针
    • 做题心得
    • 自我实现
  • 小结

题目:704. 二分查找

链接: leetcode题目链接

给定一个 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

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

实现算法:二分法

1.左闭右闭 [ left, right ]

区间定义左闭右闭,
left = 0;
right = nums.size-1;
基准判断的标准是定义区间是否合法,
left <= right
每次更新范围的时候,不包括上次边界,
left = middle + 1;
right = middle - 1;

// 1.左闭右闭
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;
    }
};

2.左闭右开 [ left, right )

区间定义左闭右开,
left = 0;
right = nums.size;
基准判断的标准是定义区间是否合法,
left <=right
每次更新范围的时候,不包括上次边界,
left = middle + 1;
right = middle ;

// 左闭右开
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;
    }
};

p.s.
如果怕middle 计算越界,可以
middle = middle + ( right - left ) / 2;

做题心得

自我实现没有成功,主要原因是边界判断不对,middle陷入了死循环,只有一个元素的时候,无限循环,且没有办法跳到判断数组中没有的元素的return -1。
最后自我实现采用了左闭右开算法。整体来说左闭右闭算法更好记,因为两边界处理方式一样。

27. 移除元素

双指针

例如:

  • Bert
  • GPT 初代
  • GPT-2
  • GPT-3
  • ChatGPT

双指针

快慢指针
快指针实现遍历,并判断各个取值是否符合条件。
慢指针实现数组更新,最后慢指针下标刚好为符合条件新数组长度

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int len = nums.size();

        int slow = 0;

        for (int fast = 0; fast < len; fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                cout << nums[slow];
                slow++;
            }
        }
        return slow;
        
    }
};


int main() {
    int a[] = { 3,2,2,3 };
    int val = 3;
    vector<int> nums(a, a + sizeof(a) / sizeof(int));
    Solution solution;
    solution.removeElement(nums, val);
}

做题心得

自我实现虽然成功了,但是用的库函数。快慢指针基本掌握了,但是时间复杂度还是挺高的。双向指针还是有问题,没有输出,感觉思路没有缕清,后续指针模块重点研究吧。

自我实现

思路:
利用vector特性,遍历数组,与val不等,则在数组后拷贝,与val相等,就积累次数v,最后返回长度为,数组原长度nums.length - 积累次数v,最后返回数组是添加了无val的长数组去掉前面原数组。

重要语法: nums.push_back(i); nums.erase(nums.begin(),nums.begin()+length);

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
    int len = nums.size();
        int v = 0;
       
        for (int i=0; i < len; i++) {
            if (nums[i] != val) {
                nums.push_back(nums[i]);
            }
            else  v++; 
            
        }
        nums.erase(nums.begin(), nums.begin() + len);
        
        return len - v;
    }
};

小结

第一天刷了好久,应该有五六个小时,也只刷了基础,不过是从自我实现一步一步走的,希望后面能好转吧!

你可能感兴趣的:(笔试,c++,leetcode)