labuladong算法公众号学习笔记
快慢指针的常见算法
链表中是否有环
boolean hasCycle(ListNode head){
ListNode fast,slow;
fast = slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow) return true;
}
return false;
}
已知链表中有环,返回这个环的起始位置
ListNode detectCycle(ListNode head){
ListNode fast,slow;
fast = slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow) break;
}
slow = head;
while(slow != fast){
fast = fast.next;
slow = slow.next;
}
return slow;
}
第一次相遇时,若慢指针slow走了k步,则快指针走了2k步,即fast一定比slow多走了k步,而k的值一定是环长度的整数倍。
假设相遇点矩环的起点的距离为m,则环的起点距头结点head的距离为k-m。同时,如果从相遇的点继续前进k-m步也恰好到达环起点。所以只要我们把快慢指针中的任一一个重新指向head,两个同速前进,k-m步就会相遇,相遇出就是环的起点。
寻找链表中点
ListNode middleNode(ListNode head){
ListNode fast,slow;
fast = slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
当快指针到达链表尽头时,慢指针刚好处于链表中间。且如果链表长度为奇数,slow恰好停在中点的位置;如果为偶数,则slow的位置为中间偏右。
寻找链表第n个元素
还是使用快慢指针,先让快指针走n步,然后快慢指针同速前进,当快指针达到链表末端时,慢指针的位置刚好是第n个元素的位置。
ListNode removeNthFromEnd(ListNode head){
ListNode fast,slow;
fast = slow = head;
while(n --> 0){//n --> 0意思是循环n次,还可以写为--n >= 0
fast = fast.next;
}
if(fast == null){
//如果此时快指针走到了头,则说明倒数第n个节点就是第一个节点
return head.next;
}
//快慢指针同速前进
while(fast != null && fast.next != null){
fast = fast.next;
slow = slow.next;
}
//slow.next就是倒数第n个节点,删除即可
slow.next = slow.next.next;
return head;
}
左右指针常用算法
左右指针在数组中是两个索引值,一般初始化为left = 0,right = nums.length - 1。
二分查找
int binarySearch(int[] nums,int target){
int left = 0;
int right = nums.length - 1;
while(left != right){
int mid = (right + left) / 2;
if(nums[mid] == target) return mid;
else if(nums[mid] > target) right = mid -1;
else if(nums[mid] < target) left = mid + 1;
}
return -1;
}
两数之和
只要数组有序,就应该想到双指针,通过调节left和right可以调节sum的大小。
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};//题目要求的索引是从1开始的。
else if(sum < target) left++;//sum大一点
else if(sum > target) right--;//sum小一点
}
return new int[]{-1,-1};
}
反转数组
void reverseString(char[] arr){
int left = 0,right = arr.length - 1;
while(left < right){
//交换arr[left]和arr[right]
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;right--;
}
}