一、知识点介绍
双指针是一种思想不是一种具体的算法
就是用两个变量动态存储两个结点
常见的双指针方式有:同速指针、快慢指针(判断链表里面有没有环)
二、练习题目
(1) 2000. 反转单词前缀
(2) 917. 仅仅反转字母
(3) 475. 供暖器
(4) 面试题 16.06. 最小差
三、算法思路
1. 反转单词前缀
(1) 找到目标字符的位置,并用一个变量储存下来
(2) 通过reverse函数,直接反转
reverse(First, Last) => [First, Last)=>reverse(nums.begin(), nums.begin())
reverse(nums.begin(), nums.begin()+i)
class Solution {
public:
string reversePrefix(string word, char ch) {
int now = 0;
for(int i = 0; i < word.size(); ++i) {
if(word[i] == ch) {
now = i;
break;
}
}
reverse(word.begin(), word.begin() + now+1);
return word;
}
};
2. 仅仅反转字母
(1) 一个指针指向数组的第一个元素,一个指针指向数组的最后一个元素。如果都指向字母的话,就交换,并移动指针
(2) 如果不是字母的话就直接移动指针
(3) 需要判断特殊情况,如果只有一个元素的话,直接返回该字符串
(4) 通过ASCII码判断该元素是不是字母:小写字母([97,122]),大写字母([65, 90])
class Solution {
public:
string reverseOnlyLetters(string s) {
int len = s.size();
int l = 0, r = len - 1;
if(len <= 1) return s;
while(l <= r) {
if(isLetter(s[l]) && isLetter(s[r])) {
swap(s[l], s[r]);
l++;
r--;
}
if(!isLetter(s[l])) l++;
if(!isLetter(s[r])) r--;
}
return s;
}
bool isLetter(char ch) {
if(ch < 'A' || ch > 'z' || (ch > 'Z' && ch <'a')) return false;
return true;
}
};
3. 供暖器
(1) 首先要保证两个数组是有序的。
(2) 遍历房子的位置,再遍历加热器的位置,将加热器离该房子的最近位置保存下来,求最大值。但是这样的话,会有很多重复计算,会超时。
(3) 所以可以用双指针或者二分查找去优化第二个循环
(4) 对于第一个数组中的每个数,二分去第二个数组找到小于等于它的最大值,这样就可以找到离自己近的数了
(5) 最后对所有的距离取最大值,就是最小半径了
class Solution {
public:
int findRadius(vector<int>& houses, vector<int>& heaters) {
int x, i, j;
int ret = 0;
sort(houses.begin(), houses.end());
sort(heaters.begin(), heaters.end());
for(i = 0; i < houses.size(); ++i) {
if(houses[i] < heaters[0]) {
x = heaters[0] - houses[i];
}else if(houses[i] > heaters.back()) {
x = houses[i] - heaters.back();
}else{
int l = 0;
int ans = -1;
int r = heaters.size() - 1;
while(l <= r) {
int mid = (l+r)>>1;
if(heaters[mid] <= houses[i]) {
l = mid + 1;
ans = mid;
}else{
r = mid - 1;
}
}
if(ans == heaters.size() - 1) {
x = houses[i] - heaters[ans];
}else{
x = min(houses[i] - heaters[ans], heaters[ans + 1] - houses[i]);
}
}
ret = max(ret, x);
}
return ret;
}
};
4. 最小差
(1) 这道题也是先要对两个数组排序(从小到大)
(2) 然后两个指针分别指向两个指针的第一个元素,两个元素做差(第一个数组的数减去第二个数组的数),如果结构大于0,那么说明,第一个数组的数大于第二个数组的数,所以就把第二个数组的指针向右移动。
(3) 同样的,第二个如果差值小于0 的话,那么说明第一个数组的数字大于第二个数组的数字,所以第一个数组的指针往右移动。
(4) 如果相等的话,说明差值最小,就直接返回0
(5) 维护一个栈,当栈为空的时候,往里面插入差值的绝对值(abs(sum);当栈不为空的时候,每次都把差值的绝对值和栈顶元素进行对比,如果小于栈顶元素的话,就插入,最后返回栈顶元素,就能保证返回的是最小值。
class Solution {
public:
int smallestDifference(vector<int>& a, vector<int>& b) {
sort(a.begin(), a.end());
sort(b.begin(), b.end());
int l = 0, r = 0;
stack<long long> ans;
while(l < a.size() && r < b.size()) {
long long sum = a[l] - b[r];
if(sum > 0) {
r++;
}else if (sum < 0) {
l++;
}else{
return 0;
}
if(ans.empty()) {
ans.push(abs(sum));
}else{
if(abs(sum) < ans.top()){
ans.push(abs(sum));
}
}
}
return ans.top();
}
};