二、玩转双指针
双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多个数组的多个指针。
若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域称为窗口),经常用于区间搜索。
若两个指针指向同一数组,但是遍历方向相反,则可用来进行搜索,待搜索的数组往往是排好序的。
1 Two sum(167)
https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/submissions/
数组是排序好的,所以可以设置两个指针分别从两端开始遍历,进行判断。有点类似二分查找的感觉。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int low = 0, high = numbers.size() - 1;
while (low < high){
if (numbers[low] + numbers[high] == target) return vector<int>{low+1, high+1};
else if (numbers[low] + numbers[high] < target) low++;
else high--;
}
return vector<int>{low+1, high+1};
}
};
2 Merge Sorted Array(88)归并两个有序数组
https://leetcode-cn.com/problems/merge-sorted-array/submissions/
使用–的技巧,n-- 先将n的值进行计算,然后减1
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int pos = m-- + n-- - 1;
while (n >= 0 && m >= 0){
nums1[pos--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];
}
while (n >= 0){
nums1[pos--] = nums2[n--];
}
}
};
3 142.环形链表||
https://leetcode-cn.com/problems/linked-list-cycle-ii/
用了快慢指针的思想。
先判断是否存在环,然后再判断环的入口结点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
do{
if (!fast || !fast->next) return NULL;
slow = slow->next;
fast = fast->next->next;
}while(fast != slow);
fast = head;
while (fast != slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}
};
4 76.最小覆盖子串
利用双指针思想,先定义一个向量存储每个字符出现的次数,然后进行对字符串s进行遍历。每次遍历判断当前对字符是不是t中的字符(见行11),减1是因为,遍历过了,需要让临时数组里的值减1.然后下面的while循环是为了判断当前获得子字符串是否是最短的字符串,思路就是定义一个min_size用来记录最短的子字符串长度,然后将左边的指针l想右移动,来判断是否满足条件,来判断。同时记录下min_size 情况下的左边的坐标即min_l,最后用c++的内置方法,s.substr(min_l, min_size)来得到子字符串。
class Solution {
public:
string minWindow(string s, string t) {
vector<int> chars(128, 0); // chars表示t中存在的字符的个数。
for (int i = 0; i< t.size(); i++){
flag[t[i]] = true;
chars[t[i]]++;
}
int l = 0, r = 0, res = 0, min_l = 0, min_size = s.size() + 1;
for (; r < s.size(); r++){
if (--chars[s[r]] >= 0){
res++;
}
while (res == t.size()){
if (r - l + 1 < min_size){
min_size = r - l + 1;
min_l = l;
}
if (++chars[s[l]] > 0){
res--;
}
l++;
}
}
return min_size > s.size()? "": s.substr(min_l, min_size);
}
};
5 633.平方数之和
class Solution {
public:
bool judgeSquareSum(int c) {
long l = 0;
long r = (long)sqrt(c);
long s = 0;
while (l <= r){
s = l * l + r * r;
if (s == c) return true;
if (s < c) l++;
else r--;
}
return false;
}
};
6 680.验证回文字符串||
class Solution {
public:
bool judge(string s, int l, int r) {
while (l < r){
if (s[l] != s[r]) return false;
l++;
r--;
}
return true;
}
bool validPalindrome(string s) {
int l = 0, r = s.size() - 1;
while (l < r){
if (s[l] != s[r]){
return judge(s, l + 1, r) || judge(s, l, r - 1);
}
l++;
r--;
}
return true;
}
};
7 524.通过删除字母匹配到字典里最长单词
class Solution {
public:
bool judge(string s, string di){
int i = 0, j = 0;
while (i < s.size() && j < di.size()){
if (s[i] == di[j]){
i++;
j++;
}else {
i++;
}
}
return j == di.size();
}
string findLongestWord(string s, vector<string>& d) {
if (s.empty()) return "";
string str = "";
for (int i = 0; i < d.size(); i++){
int tag = str.size();
int leng = d[i].size();
if (tag > leng || (tag == leng && str.compare(d[i]) < 0)) continue;
if (judge(s, d[i])){
str = d[i];
}
}
return str;
}
};