双指针_Easy

文章介绍了多种利用双指针、哈希集合解决数组问题的算法,如寻找算术三元组、翻转图像、交替合并字符串等,并提供了代码实现。同时,讨论了字符串处理问题,如反转单词、按奇偶排序数组等,展示了不同的解题思路和优化方法。
摘要由CSDN通过智能技术生成

双指针专题

在这里插入图片描述

2367. 算术三元组的数目

简单:题目描述
暴力求解:

int arithmeticTriplets1(vector<int>& nums, int diff) {
    int ans = 0, len = nums.size();
    for (int i = 0; i < len; ++i) {
        for (int j = i+1; j < len; ++j) {
            if (nums[j] - nums[i] != diff) {
                continue;
            }
            // 相等,再找下一位
            for (int k = j+1; k < len; ++k) {
                if (nums[k] - nums[j] == diff) {
                    ans++;
                }
            }
        }
    }
    return ans;
}

查找数组中有没有所需元素:

// map 集合
// 为了快速判断一个元素是否在数组中可以使用哈希集合存储数组中的所有元素
// 然后判断元素是否在哈希集合中
int arithmeticTriplets2(vector<int>& nums, int diff) {
    int ans = 0, len = nums.size();
    unordered_set<int> hashSet;
    for (int x : nums) {
        hashSet.emplace(x);
    }
    /**
     * 判断 x + diff 和 x + 2diff 是否在元素集合中
     */
    for (int x : nums) {
        if (hashSet.count(x+diff) && hashSet.count(x+2*diff)) {
            ans++;
        }
    }
    return ans;
}

三指针:

/**
 * 由于不包含重复元素 可以考虑三指针的方法
 * 需要注意的是 j 在 i之后  k 在 j之后
 */
int arithmeticTriplets3(vector<int>& nums, int diff) {
    int ans = 0;
    int len = nums.size();
    for (int i = 0, j = 1, k = 2; i < (len - 2) && j < (len - 1) && k < len; ++i) {
        j = max(j, i + 1); // 保证 j 在 i 之后
        while (j < len - 1 && nums[j] - nums[i] < diff) {
            j++;
        }
        if (nums[j] - nums[i] > diff || j == len - 1) {
            continue;
        }
        k = max(k, j + 1); // 保证 k 在 j 之后
        while (k < len && nums[k] - nums[j] < diff) {
            k++;
        }
        if (nums[k] - nums[j] == diff && k < len) {
            ans++;
        } else {
            continue;
        }
    }
    return ans;
}

832. 翻转图像

vector<vector<int>> flipAndInvertImage(vector<vector<int>>& image) {
    for (int i = 0; i < image.size(); ++i) {
        vector<int> &temp = image[i];
        for(int left=0,right=temp.size()-1; left<right;++left,--right){
            swap(temp[left], temp[right]);
        }
        for (int j = 0; j < temp.size(); ++j) {
            temp[j] = temp[j] == 1 ? 0 : 1;
        }
    }
    return image;
}

1768. 交替合并字符串

class Solution {
public:
    string mergeAlternately(string word1, string word2) {
        string ans;
        int len1 = word1.size(), len2 = word2.size();
        int i = 0;
        for (i = 0; i < min(len1, len2); i++) {
            ans += word1[i];
            ans += word2[i];
        }
        // 判断二者哪个为空把另一个追加
        if (i == len1) {
            for (int j = len1; j < len2; ++j) {
                ans += word2[j];
            }
        }
        if (i == len2) {
            for (int j = len2; j < len1; ++j) {
                ans += word1[j];
            }
        }
        return ans;
    }
};

942. 增减字符串匹配

不错的题目:本题实质是有一种贪心的思想在其中的

class Solution {
public:
    vector<int> diStringMatch(string s) {
        int n = s.size();
        vector<int> perm(n + 1);
        int start = 0, end = n;
        for (int i = 0; i < n; ++i) {
            perm[i] = s[i] == 'I' ? start++ : end--;
        }
        perm[n] = start;
        return perm;
    }
};

349. 两个数组的交集

介绍一种找两个集合交集的方法:

如果两个数组是有序的,则可以使用双指针的方法得到两个数组的交集。

首先对两个数组进行排序,然后使用两个指针遍历两个数组。可以预见的是加入答案的数组的元素一定是递增的,为了保证加入元素的唯一性,我们需要额外记录变量pre 表示上一次加入答案数组的元素。

初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 pre,将该数字添加到答案并更新 pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。

vector<int> intersection2(vector<int>& nums1, vector<int>& nums2) {
    sort(nums1.begin(), nums1.end());
    sort(nums2.begin(), nums2.end());
    int len1 = nums1.size(), len2 = nums2.size();
    int index1 = 0, index2 = 0;
    int pre = 0; // 用于保证升序
    vector<int> res;
    while (index1 < len1 && index2 < len2) {
        if (nums1[index1] > nums2[index2]) {
            index2++;
        } else if (nums1[index1] < nums2[index2]) {
            index1++;
        } else {
            // 二者相等
            pre = nums1[index1];
            if (res.size() > 0) { // res 不为空
                if (res.back() != pre) {
                    res.push_back(pre);
                }
            } else {
                // 当前 res 中不包含元素
                res.push_back(pre);
            }
            index1++;
            index2++;
        }
    }
    return res;
}

557. 反转字符串中的单词 III

class Solution {
public:
    void reverse(string &str, int left, int right) {
        for (int start=left,end=right;start<end;++start,--end) {
            swap(str[start], str[end]);
        }
    }
    string reverseWords(string s) {
        int start = 0, end = 0;
        int last_index = 0;
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != ' ') {
                last_index = i;
            }
            if (s[i] == ' ') {
                end = i-1;
                if (start>=0 && end<s.size()) {
                    reverse(s, start, end);
                }
                start = i+1;
            }
        }
        if (last_index == s.size() - 1) {
            reverse(s, start, last_index);
        }
        return s;
    }
};

2562. 找出数组的串联值

就是将数字以字符串形式拼接后求和

class Solution {
public:
    int getCnt(int num) {
        int cnt = 0;
        while (num > 0) {
            cnt++;
            num /= 10;
        }
        return cnt;
    }
    long long findTheArrayConcVal(vector<int>& nums) {
        long long res = 0;
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int cnt = getCnt(nums[right]);
            res += (nums[left] * (long long)pow(10, cnt) + nums[right]);
            left++;
            right--;
        }
        if (right == left) {
            res += nums[left];
        }
        return res;
    }
};

922. 按奇偶排序数组 II

先看我的解法,有点笨:
思想是碰到一个不满足要求的数组元素后就意味着后面肯定还会出现一个不满足要求的数组元素(因为数组长度为偶数且奇偶各占一半),所以在遇到情况不满足要求的数组元素是我就记录其下标,然后再后面查找下一个不满足要求的元素将二者进行交换使其恰好满足题目要求。

vector<int> sortArrayByParityII(vector<int>& nums) {
    int n = nums.size();
    for (int i = 0; i < n; ++i) {
        if (i % 2 == 0 && nums[i] % 2 != 0) {
            // 偶数
            int index = i;
            // 找奇数
            for (int j = index + 1; j < n; ++j) {
                if (j % 2 != 0 && nums[j] % 2 == 0) {
                    swap(nums[i], nums[j]);
                    break;
                }
            }
        } else if(i % 2 != 0 && nums[i] % 2 == 0) {
            int index = i;
            // 找偶数
            for (int j = index + 1; j < n; ++j) {
                if (j % 2 == 0 && nums[j] % 2 != 0) {
                    swap(nums[i], nums[j]);
                    break;
                }
            }
        }
    }
    return nums;
}

下面看官方提供的这种双指针思路,我感觉不错:

class Solution {
public:
    vector<int> sortArrayByParityII(vector<int>& nums) {
        int n = nums.size();
        int j = 1;
        for (int i = 0; i < n; i += 2) {
            if (nums[i] % 2 == 1) {
                while (nums[j] % 2 == 1) {
                    j += 2;
                }
                swap(nums[i], nums[j]);
            }
        }   
        return nums;
    }
};

下面看类似问题,根据就行进行排序,要取偶数在前奇数在后:

class Solution {
public:
    vector<int> sortArrayByParity(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n);
        int left = 0, right = n - 1;
        for (auto & num : nums) {
            if (num % 2 == 0) {
                res[left++] = num;
            } else {
                res[right--] = num;
            }
        }
        return res;
    }
};

2570. 合并两个二维数组 - 求和法

题目描述,采用归并排序的思想求解即可:

class Solution {
public:
    vector<vector<int>> mergeArrays(vector<vector<int>>& nums1, vector<vector<int>>& nums2) {
        vector<vector<int>> res;
        int n = nums1.size(), m = nums2.size();
        int i = 0, j = 0;
        while (i < n && j < m) {
            vector<int> temp;
            if (nums1[i][0] == nums2[j][0]) {
                temp.push_back(nums1[i][0]);
                temp.push_back(nums1[i][1] + nums2[j][1]);
                res.push_back(temp);
                i++;
                j++;
            } else if (nums1[i][0] > nums2[j][0]) {
                res.push_back(nums2[j]);
                j++;
            } else if (nums1[i][0] < nums2[j][0]) {
                res.push_back(nums1[i]);
                i++;
            }
        }

        while (i < n){
            res.push_back(nums1[i++]);
        }
        while (j < m){
            res.push_back(nums2[j++]);
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值