双指针法
1. 移除元素
思路:
第一个 right 指针向右遍历数组,遇到 val 跳过,right 指针向右移动;
否者将 right 处的值放入 left 中,left 和 right 一起往后移动。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int nums_size = nums.size();
int left = 0, right = 0;
while (right < nums_size) {
if (nums[right] != val) {
nums[left++] = nums[right];
}
right++;
}
return left;
}
};
2. 反转字符串
思路:
首尾交换,指针向中间移动。
class Solution {
public:
void reverseString(vector<char>& s) {
int s_len = s.size();
int left = 0, right = s_len - 1;
while (left < right) {
swap(s[left++], s[right--]);
}
}
};
5. 反转链表
思路:
记录第三个节点的位置tmp,将第二个指针指向第一个指针,然后指针整体后移。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr) return head;
ListNode *cur = head;
ListNode *tmp = cur->next;
ListNode *pre = NULL;
while (cur) {
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
6. 环形链表 II
思路:
设置两个指针,slow 每次走一步,fast 每次走两步,如果无环可直接判断。
如果有环,则找到 slow 和 fast 的交点。然后 slow 回到 head 处,fast 步幅改为 1,重新同时出发,直到相遇,此处为环形入口。
数学依据:
2 * (x + y) = x + y + n(y + z)
x - z = (n - 1)(y + z)
即相遇后,从起点和交点同时出发,相当于一个追击问题,追击距离为x - z
,正好是n - 1
圈 的长度,即走n - 1
圈后一定会在环形入口处相遇。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (head == NULL || head->next == NULL) return NULL;
ListNode *fast = head;
ListNode *slow = head;
while (fast != NULL && fast->next != NULL) { // 只需要快指针不为空即可
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
}
return NULL;
}
};