LeetCode 24 两两交换链表中的结点
关于交换链表中结点的问题最好是通过画图的方式来确定交换的顺序,然后再写代码,这样才能保证代码的正确率。
这题有迭代和递归两种方式:
迭代:
public ListNode swapPairs(ListNode head) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode cur = dummyNode;
ListNode temp;
ListNode firstNode;
ListNode secondNode;
while(cur.next!=null&&cur.next.next!=null){
temp=cur.next.next.next;
firstNode =cur.next;
secondNode = cur.next.next;
cur.next = secondNode;
secondNode.next = firstNode;
firstNode.next = temp;
cur = firstNode;
}
return dummyNode.next;
}
递归:
class Solution {
public ListNode swapPairs(ListNode head) {
// base case 退出提交
if(head == null || head.next == null) return head;
// 获取当前节点的下一个节点
ListNode next = head.next;
// 进行递归
ListNode newNode = swapPairs(next.next);
// 这里进行交换
next.next = head;
head.next = newNode;
return next;
}
}
LeetCode 19 删除倒数第n个结点
这题主要是应用双指针的思想,让快指针先向前运行n个结点,然后让慢指针和快指针同时移动,直至快指针到达最后一个结点。
需要注意的是,同时移动时循环的条件是判断快指针的下一个为不为空,因为最后一个结点代表的是倒数第1个结点。这样才能够保证在确保cur.next.next不为空
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode fast = dummyNode;
ListNode slow = dummyNode;
for(int i =0;i<n;i++){
fast = fast.next;
}
while(fast.next!=null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummyNode.next;
}
LeetCode 面试题2.07 链表相交问题
对于链表相交问题我们需要确定两个链表的长度,如果链表有相交部分,那么他们非相交部分的长度区别才会导致总体长度有所却别。所以我们可以先计算出两个链表的长度,然后削减长的链表的长度,让两个链表的长度相同,这样再让让两个结点从初始点出发,如果两个链表相交,那么他们一定存在相等的时候,否则则不存在相交结点。
ublic ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode startA = headA;
ListNode startB = headB;
int lenA = 1;
int lenB = 1;
while(startA!=null){
lenA++;
startA = startA.next;
}
while(startB!=null){
lenB++;
startB = startB.next;
}
startA = headA;
startB = headB;
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (startA, startBB);
ListNode tmpNode = startA;
startA = startB;
startB = tmpNode;
}
int gap = lenA-lenB;
while(gap-->0){
startA = startA.next;
}
while(startA!=null){
if(startA == startB){
return startA;
}
startA = startA.next;
startB = startB.next;
}
return null;
}
LeetCode 142 环形链表||
判断链表是否有环问题主要是通过快慢指针的方式来进行的:快指针每次移动两格,慢指针每次移动一格。如果有环,那么两格结点一定会相遇。图示如下
寻找链表环的起点:在快慢指针相遇时:
slow指针走过的节点数为: x + y
, fast指针走过的节点数:x + y + n (y + z)
,n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。
因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:
(x + y) * 2 = x + y + n (y + z)
两边消掉一个(x+y): x + y = n (y + z)
因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。
所以要求x ,将x单独放在左面:x = n (y + z) - y
,
再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z
注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针。
所以我们再设置两个指针,一个指针从head开始移动,一个指针从相遇点开始移动,两个指针相遇的位置一定是环的起始点。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(fast ==slow){
ListNode index1 = fast;
ListNode index2 = head;
while(index1!=index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
总结:
链表相关的问题就告一段落了,在解决链表问题的过程中我们也使用了快慢指针的思想。比如在删除倒数第n个结点的问题中:我们先让快指针移动n个节点的距离,然后再同时移动,这样我们就能保证在快指针抵达最后一个位置的时候,慢指针的位置一定是需要删除结点的前一个位置,这样我们就能够进行删除操作了。
环形链表问题中:我们先通过如果有环那么移速不同的两个指针一定会相遇来判断链表是否有环。再根据数学分析确定,如果此时有两个指针一个从头结点出发,一个从当前结点出发,这两个结点相遇的位置一定是环的起始位置来寻找环的起点。
然后我们还接触了递归和迭代两种方式,我对这两种方式掌握的还不是很熟练,还需要多加练习。对于环形链表这种问题需要不定期的反复练习来增强记忆