算法训练营第一天(7.12)| 数组Part01:二分算法&双指针 (含模板)

目录

二分算法

算法模板

等值问题模板:

1. 闭区间求法模板

2. 左闭右开区间模板

区间问题模板

1. 闭区间求法模板

2. 左闭右开区间模板

LeeCode704. Binary Search

LeeCode35. Search Insert Position

LeeCode34. Find First and Last Position of Element in Sorted Array

 

双指针

LeeCode27.Remove Element


二分算法

二分算法分为两种大类别:等值类型和区间类型

  1. 等值类型:即有序数组中的每个值是唯一的,需要求出该值在数组中的具体位置
  2. 区间类型:即有序数组中的每个值可能有多个,需要求出第一个和最后一个出现的位置
    1. ≥ 问题:求 ≥x
    2. >问题:求 ≥x+1
    3. ≤ 问题:求 ≤ (≥x+1)
    4. <问题:求<(≥x)

算法模板

等值问题模板:

1. 闭区间求法模板

public:
    int searchInsert(vector& nums, int target) {
        // 闭区间
        int l = 0, r = nums.size() - 1;
        while (l <= r) {
            int mid = (r - l) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid - 1;
            else l = mid + 1;
        }
        return l;
    }

2. 左闭右开区间模板

public:
    int searchInsert(vector& nums, int target) {
        // 左闭右开
        int l = 0, r = nums.size();
        while (l < r) {
            int mid = (r - l) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid;
            else l = mid + 1;
        }
        return l;
    }

区间问题模板

1. 闭区间求法模板

public:
    int getStart(vector& nums, int target) {
        // 采用闭区间写法获得第一次出现的位置
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (r - l) / 2 + l;
            // 接下来寻找的区间:[mid + 1 , r]
            if (nums[mid] < target) l = mid + 1;
            // 包含nums[mid] == target的情况,由于要寻找第一次出现的位置,所以就算找到了,也要继续向左寻找  接下来寻找的区间:[l, mid - 1]
            else r = mid - 1;
        }
        return l;
    }

2. 左闭右开区间模板

public:
    int getStart1(vector& nums, int target) {
        // 采用左闭右开区间写法获得第一次出现的位置
        int n = nums.size();
        int l = 0, r = n;
        while (l < r) {
            int mid = (r - l) / 2 + l;
            // 接下来寻找的区间:[mid + 1, r)
            if (nums[mid] < target) l = mid + 1;
            // 接下来寻找的区间:[l, mid)
            else r = mid; 
        }
        return l;
    }

LeeCode704. Binary Search

题目地址:704​​​​​

题目类型:二分等值问题

算法训练营第一天(7.12)| 数组Part01:二分算法&双指针 (含模板)_第1张图片

思路:一个很标准的闭区间等值问题,直接AC。

class Solution {
public:
    // 一个升序排列的数组nums
    int search(vector& nums, int target) {
        int l = 0, r = nums.size() - 1;
        // 此处要加上一个等号,因为要考虑到nums长度为1的情况
        while (l <= r) {
            int mid = (r - l) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] < target) l = mid + 1;
            else r = mid - 1;
        }
        return -1;
    }
};

LeeCode35. Search Insert Position

题目地址:力扣

题目类型:二分等值问题

算法训练营第一天(7.12)| 数组Part01:二分算法&双指针 (含模板)_第2张图片

 思路:寻找插入位置等价于寻找target应当在数组中出现的位置,即等值问题,可以采用闭区间和左闭右开区间两种方法求解。

1. 闭区间解法

class Solution {
public:
    int searchInsert(vector& nums, int target) {
        // 闭区间
        int l = 0, r = nums.size() - 1;
        while (l <= r) {
            int mid = (r - l) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid - 1;
            else l = mid + 1;
        }
        return l;
    }
};

2. 左闭右开区间解法

class Solution {
public:
    int searchInsert(vector& nums, int target) {
        // 左闭右开
        int l = 0, r = nums.size();
        while (l < r) {
            int mid = (r - l) / 2 + l;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > target) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

LeeCode34. Find First and Last Position of Element in Sorted Array

题目地址:力扣

题目类型:二分区间问题

算法训练营第一天(7.12)| 数组Part01:二分算法&双指针 (含模板)_第3张图片

思路:本题一共需要求两个值:

  1. ≥ target 的下界,即第一次出现的位置;
  2. ≤ target 的上界,即最后一次出现的位置。

看似需要分别来求以上两个子问题,实际上当求出≥ target,直接使用 ≤ (≥ target+1) - 1 即可。

故直接编写求解子问题1的函数getStart(nums, target),使start = getStart(nums, target),使end = getStart(nums, target + 1) - 1。

class Solution {
private:
// getStart方法对应的都是求>=target的边界值
    int getStart(vector& nums, int target) {
        // 采用闭区间写法获得starting position
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (r - l) / 2 + l;
            // [mid + 1 , r]
            if (nums[mid] < target) l = mid + 1;
            // 包含nums[mid] == target的情况,由于要寻找第一次出现的位置,所以就算找到了,也要继续向左寻找 [l, mid - 1]
            else r = mid - 1;
        }
        return l;
    }
    int getStart1(vector& nums, int target) {
        // 采用左闭右开区间写法获得starting position
        int n = nums.size();
        int l = 0, r = n;
        while (l < r) {
            int mid = (r - l) / 2 + l;
            // [mid + 1, r]
            if (nums[mid] < target) l = mid + 1;
            else r = mid; 
        }
        return l;
    }

public:
    vector searchRange(vector& nums, int target) {
        // start是>=target的边界值, end是<=target的边界值,end即求:>=target + 1对应的start,然后<= start - 1
        int start, end;
        start = getStart(nums, target);
        if (start == nums.size() || nums[start] != target) return {-1, -1};
        end = getStart1(nums, target + 1) - 1;
        return {start, end};
    }
};


双指针

LeeCode27.Remove Element

题目地址:力扣

题目类型:双指针

 思路:要使用O(n)的时间复杂度实现原地修改数组,第一眼要想到的就是上指针,没什么好说的,很标准很简单的一道题,直接AC。

class Solution {
public:
    int removeElement(vector& nums, int val) {
        // i和j代表左右指针,count用于计数
        int i = 0, j = 0, count = 0;
        while (j < nums.size()) {
            if (nums[j] != val) {
                swap(nums[i], nums[j]);
                i++;j++;
            }
            else {
                j++;
                count++;
            }
        }
        return nums.size() - count;
    }
};

第一次认真写博客,大概写了一两个小时,希望对有需要的人能有所帮助,这次的训练也让我对binary search有了更加透彻的理解,不过也深知还有许多未能探讨的到的地方,继续努力。

你可能感兴趣的:(算法训练营,算法,c++,学习,leetcode,数据结构)