核心思想: 将需要O(n²)的双重循环优化到O(n)
模板:
for(int i = 0, j = 0; i <= n; i++){
while(j < i && check(i, j))j++;
}
双指针例题
leecode 3. 无重复字符的最长子串
主要的思路是用两个指针做头尾,并向后移动。当子串重复出现时,一定是与头指针的元素重复(因为子串是连续的),因此尾指针向后移动,头指针向后移动(删除头指针元素)
int lengthOfLongestSubstring(string s) {
int res = 0;
vector<int>temp(105, 0);
for(int i = 0, j = 0; i < s.size(); i++){
temp[(s[i] - '0' + 103) % 103]++;
while(temp[(s[i] - '0' + 103) % 103] > 1){//判断是否出现了重复元素
temp[(s[j] - '0' + 103) % 103]--;
j++;
}
res = max(res, i - j + 1);
}
return res;
}
这里注意,因为s中含有字符和空格,转换为int后会出现复数,需要取模。
leecode 283.移动零(首刷)
空间占用的有点多
void moveZeroes(vector<int>& nums) {
int start = 1e4 + 10;
for(int i = 0; i < nums.size(); i++){
if(!nums[i]){
start = i;
break;
}
}
for(int i = start + 1, j = start; i < nums.size(); i++){
if(nums[i]){
nums[j++] ^= nums[i];
nums[i] = 0;
while(nums[j] && j < i)j++;//j一直找到下一个为0的点
}
}
}
leecode 42. 接雨水
思路很牛逼,基本就是通过头尾双指针和短板效应约束水位最高边界,详解参考:经典面试题:接雨水问题详解 很清晰。
int trap(vector<int>& height) {
int n = height.size();
if(!n)return 0;
int left = 0, right = n - 1;//双指针
int l_max = height[0], r_max = height[n - 1];
int ans = 0;
while(left <= right){
l_max = max(l_max, height[left]);
r_max = max(r_max, height[right]);
if(l_max < r_max){
ans += l_max - height[left];
left ++;
}else{
ans += r_max - height[right];
right --;
}
}
return ans;
}
相交链表
原理:假设headA链表的单独部分和重合部分为a + c, headB链表的单独部分和重合部分为b + c,每个指针每次均向后移位,分别将两个链表遍历一遍:
- 若每个指针将两个链表遍历结束之后还是没有相交,则两个链表无相交的地方。
- 若某个指针将其中一个链表遍历结束后,指向另一个链表的头部紧接着遍历。
- 这样能找到遍历的节点,因为ptr1停下时走过了 a + c + b, ptr2停下时走过了 b + c + a
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(!headA || !headB)return nullptr;
ListNode* ptr1 = headA,*ptr2 = headB;
while(ptr1 != ptr2){
ptr1 = (ptr1 ? ptr1->next : headB);
ptr2 = (ptr2 ? ptr2->next : headA);
}
return ptr1;
}
leecode 11.盛水最多的容器
跟接雨水的题目很像,但是简单很多很多,不过接雨水是要考虑左右边界的高度和内部水柱的距离,而这道题简单很多,只需找到需要作为边界的左右两个柱子就行。
class Solution {
public:
int maxArea(vector<int>& height) {
int n = height.size();
if(!n)return 0;
int left = 0, right = n - 1;
int res = 0;
while(left <= right){
res = max(res, min( height[left],height[right]) * (right - left));
if(height[left] < height[right])left ++;
else right--;
}
return res;
}
};