2013-1-5 双指针

一、知识点介绍

双指针是一种思想不是一种具体的算法
就是用两个变量动态存储两个结点
常见的双指针方式有:同速指针、快慢指针(判断链表里面有没有环)

二、练习题目

        (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();
    }
};

四、 总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值