数组类型的题目是一种非常普遍的题目,根据题目不一样的,解决的策略也有很多,今天主要讲的是采用左右指针和扫描线来解决的题目类型。
左右指针
左右指针一般用来解决区间内某个值得问题,看上去非常相类似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(