双指针技巧框架
双指针技巧分为两类,一类是”快、慢指针“,一类是”左、右指针“。前者主要解决链表中的问题,比如典型的判定链表中是否包含环;**后者主要解决数组(或者字符串)**中的问题,比如二分搜索。
快、慢指针的常用算法
快、慢指针一般会初始化指向链表的头节点 head,前进时快指针 fast 在前,慢指针 slow 在后。
1、判定链表中是否有环
分析:如果链表中不含环,那么这个指针最终会遇到空指针 null,表示链表到头了。否则就是链表含环。
采用双指针,一个跑得快 fast,一个跑的慢 slow。如果不含有环,跑得快的那个指针最终会遇到 null,说明链表不含环;如果含有环,快指针最终会超慢指针1圈,和慢指针相遇,说明链表有环。
代码:
bool hasCycle(ListNode *head){
ListNode *slow = head, *fast = head;
while(fast && fast->next){
slow = slow->next; //慢指针每次前进一步
fast = fast->next->next; //快指针每次前进两步
if(slow == fast){ //存在环,则快、慢指针必然相遇
return true;
}
}
return false;
}
2、已知链表中含有环,返回这个环的起始位置
代码:
ListNode* detectCycle(ListNode *head){
ListNode *slow = head, *fast = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
break;
}
}
slow = head;
while(slow != fast){
//两个指针以相同的速度前进
slow = slow->next;
fast = fast->next;
}
//两个指针相遇的那个单链表节点就是环的起点
return slow;
}
3、寻找无环单链表的中点
分析:使用双指针技巧,快指针 fast 一次前进两步,慢指针 slow 一次前进一步,当快指针到达链表尽头时,慢指针就处于链表的中间位置。
代码:
ListNode* midListNode(ListNode *head){
ListNode *slow = head, *fast = head;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
4、 寻找单链表的倒数第 k 个元素
分析:类似寻找单链表中点,采用快、慢指针,让快指针 fast 先走 k 步,然后快、慢指针开始同速前进。这样当快指针走到链表末尾 null 时,慢指针所在的位置就是倒数第 k 个链表节点。
代码:
ListNode* findKNode(ListNode *head, int k){
ListNode *slow = head, *fast = head;
//注:这里的k的大小不会超过链表的长度
while(k--){
fast = fast->next;
}
while(fast){
slow = slow->next;
fast = fast->next;
}
return slow;
}
左、右指针常用算法
左、右指针一般运用在数组问题中,实际是指两个索引值,一般初始化为 left = 0, right = len(nums) - 1。
1、二分搜索
这个我相信大家一定很熟悉了,就不再啰嗦了,直接上代码!!!
代码:
int binarySearch(int[] nums,int target){
int left = 0, right = nums.length -1;
while(left <= right){
int mid = left+(right - left)/2; //防止相加后数字过大,造成溢出
if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid -1;
}else if(nums[mid] == target){
return mid;
}
}
return -1;
}
2、两数之和
题目:输入一个已按照升序排列的有序数组 nums 和一个目标值 target,在 nums 中找到两个数使得它们相加之和****等于 target,请返回这两个数的索引。这两个数一定存在,且索引从1 开始。
代码:
int[] twoSum(int[] nums, int target){
int left = 0, right = nums.length -1;
while(left < right){
int sum = nums[left] + nums[right];
if(sum == target){
return new int[]{left+1, right+1};
}else if(sum < target){
left++;
}else if(sum > target){
right--;
}
}
return new int[]{-1,-1};
}
3、反转数组
代码:
void reverse(int[] nums){
int left = 0, right = nums.length - 1;
while(left < right){
int temp = nums[right];
nums[right] = nums[left];
nums[left] = temp;
left++;
right++;
}
}
over!!! 开心!!!
os:整理这个真的浪费时间也 qwq