Two Pointer Problems (Part 2) - Sliding Window
Two pointers are used to scan in two directions during traversal, achieving the desired algorithmic goals.
Two pointers are used to scan in two directions during traversal, achieving the respective algorithmic goals.
In a broad sense, two pointers refer to problems solved by traversing with two variables in linear structures.
In a narrow sense:
The two-pointer approach defines the leftmost index as the left pointer (left) and the rightmost index as the right pointer (right), traversing the array from both ends towards the middle.
The two-pointer approach is suitable for sorted arrays and strings.
The time complexity of the two-pointer approach is
This problem requires rearranging the order of the array by odd and even numbers. We can use the left pointer to find odd numbers and the right pointer to find even numbers. When the left pointer finds an even number and the right pointer finds an odd number, swap the two numbers. The code is as follows:
vector<int> exchange(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
while (l < r) {
while(l < r && nums[l] % 2 == 1) l++;
while(l < r && nums[r] % 2 == 0) r--;
swap(nums[l], nums[r]);
}
return nums;
}
This problem requires finding pairs of numbers that sum to
If the pair
Similarly, if
Therefore, this problem can also be solved using the two-pointer approach. When
vector<int> twoSum(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
vector<int> ans;
while (l < r) {
while (l < r && nums[l] + nums[r] < target) l++;
while (l < r && nums[l] + nums[r] > target) r--;
if (nums[l] + nums[r] == target) {
ans.push_back(nums[l]);
ans.push_back(nums[r]);
return ans;
}
}
return ans;
}
The fast-slow pointer defines a pair of pointers with different speeds in the sequence to solve one-way sequence problems.
The time complexity of the fast-slow pointer approach is
This problem requires determining whether a linked list has a cycle. We can define a fast pointer and a slow pointer, and then move them. If the fast pointer catches up with the slow pointer, it means the linked list definitely has a cycle. The code is as follows:
bool hasCycle(ListNode *head) {
ListNode *p1 = head, *p2 = head;
do {
if (p1 && p2 && p2->next) {
p1 = p1->next;
p2 = p2->next->next;
}
else return false;
} while(p1 != p2);
return true;
}
This problem requires finding the first node of the cycle while determining if there is a cycle. We can reason based on the condition that the fast pointer’s speed is always twice that of the slow pointer.
Assuming the fast and slow pointers meet at point
Since the fast pointer’s speed is twice that of the slow pointer, we have:
which implies
Therefore, when the fast and slow pointers meet, the distance from the meeting point to the entry point of the cycle is always
ListNode *detectCycle(ListNode *head) {
ListNode *p1 = head, *p2 = head;
do {
if (p1 && p2 && p2->next) {
p1 = p1->next;
p2 = p2->next->next;
} else return NULL;
} while (p1 != p2);
ListNode *cur = head;
while (cur != p1) {
cur = cur->next;
p1 = p1->next;
}
return cur;
}