双指针,英文名two pointers
可以看作是单向双指针的优化版:对向双指针。
单向双指针定义两个下标i,j,共同向size为n数组的一个方向移动,暴力搜索通常就是这种方法,时间复杂度为(n ^ 2),通常可以优化为(n ^ 2 / 2),即每次枚举j从i + 1开始。然而也是指数级复杂度,通常是不能接受的(我可以接受,但出题人不接受)。
—————————————————————
i ➡️ j ➡️
于是衍生出对向的双指针(不知道谁发明的),即两个指针向对方进发(通常会有一个mid作为参考值)。此时i,j(通常用l,r)共同遍历一次数组,时间复杂度为(n)。化(n^2)为(n),简直不能有更优秀的优化了。
—————————————————————
i➡️ mid ⬅️j
例1:(LeetCode 1.两数之和)
给定一个单调递增的整数数组nums,要求返回和为target的所有二元组,nums中没有重复元素。
//单向双指针
vector<vector<int>> findSum(vector<int> nums, int target) {
vector<vector<int>> ans;
for(int i = 0; i < nums.size() - 1; ++i) {
for(int j = i + 1; j < nums.size(); ++j) {
if(nums[i] + nums[j] == target) {
ans.push_back({nums[i], nums[j]});
}
}
}
return ans;
}//击败用户5.2%
//双向双指针
vector<int> twoSum(vector<int> nums, int target) {
vector<int> ans;
unordered_map<int, int> hash_1;
unordered_map<int, int> hash_2;
int l = 0;
int r = nums.size() - 1;
for(int i = 0; i < nums.size(); ++i) {
if(hash_1[nums[i]]) {
hash_2[nums[i]] = i;
}else {
hash_1[nums[i]] = i;
}
}
sort(nums.begin(), nums.end());
while(l <= r) {
if(nums[l] + nums[r] > target) {
--r;
}else if(nums[l] + nums[r] < target) {
++l;
}else {
if(nums[l] == nums[r]) {
ans.push_back(hash_1[nums[l]]);
ans.push_back(hash_2[nums[r]]);
}else {
ans.push_back(hash_1[nums[l]]);
ans.push_back(hash_1[nums[r]]);
}
break;
}
}
return ans;
}//击败用户99.4%