算法之数组上的左右指针

本文详细介绍了在数组问题中使用左右指针解决各类算法题目的方法,包括夹击型、追击型和划分类型。夹击型如求两个水柱之间最大注水面积,追击型如求两个数组的最小差值,划分类型如数组元素重新排列。通过左右指针策略,可以高效地解决区间内的问题,而不需要借助额外的数据结构或多次遍历。
摘要由CSDN通过智能技术生成

数组类型的题目是一种非常普遍的题目,根据题目不一样的,解决的策略也有很多,今天主要讲的是采用左右指针和扫描线来解决的题目类型。

左右指针

左右指针一般用来解决区间内某个值得问题,看上去非常相类似DP问题,但是它和DP又有本质的区别,归纳为有以下两个特点:

  • 一个区间内或者两个元素的最大,最小,和,或者中间值,求区间内的某个数:比如求两个水柱之间最大水量,求window下的中间数,求一个数组指定和的组合
  • 左右指针是不断逼近最终结果策略,而DP是从某个或者某几个中间状态可以求到最终状态。

整个左右指针又可以分为三个类型:

  • 左右夹击类型
  • 追赶类型
  • 划分类型

夹击型

求数组中所有和为指定数的两个数?two sum
Example
numbers=[0,2,11,15,7], target=9
return [2, 7]
如果可以用附加数据结构,采用hashmap是最快的办法,可以O(n)内解决这个问题。具体做法是依次遍历数组中元素,当遍历到A[i]时,判断下target-A[i]是否在hashmap中存在,存在则直接将这两个元素插入到结果中,如果不存在则将A[i]元素压入到hashmap中,直到遍历完所有元素。
如果不能用附加数据结构,则就需要用左右指针方法,先对整个数组进行排序,快排就是一种in-place的排序算法,然后将left指针放在开始的位置,right指针放在末尾的位置
A[left]+A[right]==target则找到这样的组合
A[left]+A[right]>target则right–,因为只有right–才能将和降下来
A[left]+A[right]

class Solution {
public:
    /*
    * @param numbers : An array of Integer
    * @param target : target = numbers[index1] + numbers[index2]
    * @return : [index1+1, index2+1] (index1 < index2)
    */
    vector<int> twoSum(vector<int> &nums, int target) {
        vector<int> Result;
        if (nums.size() < 2) {
            return Result;
        }

        vector<int> NumPos(nums.size());
        for (int i = 0; i < NumPos.size(); ++i) {
            NumPos[i] = i;
        }
        sort(NumPos.begin(), NumPos.end(), [&nums](int Left, int Right) { return nums[Left] < nums[Right]; });

        int Left = 0;
        int Right = NumPos.size() - 1;
        while (Left < Right) {
            if (nums[NumPos[Left]] + nums[NumPos[Right]] == target) {
                if (NumPos[Left] > NumPos[Right]) {
                    Result.push_back(NumPos[Right]);
                    Result.push_back(NumPos[Left]);
                }
                else {
                    Result.push_back(NumPos[Left]);
                    Result.push_back(NumPos[Right]);
                }
                break;
            }
            else if (nums[NumPos[Left]] + nums[NumPos[Right]] > target) {
                Right--;
            }
            else {
                Left++;
            }
        }

        return Result;
    }
};

这道题使我想到杨氏矩阵,寻找某个target的值,将开始指针放在矩阵的右上角,如果target数比当前数小,则指针往左走,如果target数比当前述大,则指针往下走,直到指针走出整个矩阵。

注水问题

给出水柱高度,求两个水柱之间的最大注水面积
两个水柱之间的注水面积,求这两根水柱。
left指向0,right指向最后一个位置,最大面积为min(A[left], A[right])*(right-left)
A[left]>=A[right] right–,因为要有更大的面积只能提高柱子的高度,提高
A[left]

class Solution {
public:
    /**
     * @param heights: a vector of integers
     * @return: an integer
     */
    int maxArea(vector<int> &heights) {
        if( heights.size() < 2 ){
            return 0;
        }

        int left = 0;
        int right = heights.size() - 1;
        int maxContainer = 0;
        while(left < right){
            maxContainer = max(maxContainer, min(heights[left], heights[right])*(right-left));
            if(
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值