双指针专题
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;
}
};