算法训练Day03 | 24. 两两交换链表中的节点、19. 删除链表的倒数第 N 个结点、面试题 02.07. 链表相交、142. 环形链表 II
我新建的个人博客,欢迎访问:hmilzy.github.io
24. 两两交换链表中的节点
题目链接: 两两交换链表中的节点
方法一:同样设置虚拟头结点。这里需要操作的结点数很多,数四个分别为 cur、firstNode、secondNode、temp,判断循环结束的条件需要注意一下,避免出现空指针异常
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode cur = dummyhead;
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 dummyhead.next;
}
}
方法二:递归法(此处有点难以理解,需要多画图吧)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
//递归法
if(head == null || head.next == null){
return head;
}
ListNode temp = head.next;
ListNode newNode = swapPairs(temp.next);
temp.next = head;
head.next = newNode;
return temp;
}
}
19. 删除链表的倒数第 N 个结点
题目链接: 删除链表的倒数第 N 个结点
第一个思路:肯定是先遍历链表,得到链表长度。然后重新从头结点开始遍历,找到要删除结点的前一个结点即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//第一种做法当然是先遍历链表,找出链表长度。然后再遍历到倒数第n个结点附近,进行删除
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode cur = dummyhead;
int size = 0;
while(cur.next != null){
cur = cur.next;
size++;
}
//找到要删除结点的前一个结点
cur = dummyhead;
for(int i = 0; i < size - n; i++){
cur = cur.next;
}
cur.next = cur.next.next;
return dummyhead.next;
}
}
第二个方法:倒数第n个结点,可以从头节点开始,找到一个大小为n的窗口,也就是双指针。
当右指针遍历到链表尾部的时候,左指针就正好是要删除的结点的前一个结点,然后再删除即可。
多画图!!!
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode fast = dummyhead;
ListNode slow = dummyhead;
for(int i = 0;i < n + 1;i++){
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummyhead.next;
}
}
面试题 02.07. 链表相交
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA, B = headB;
while (A != B) {
A = A != null ? A.next : headB;
B = B != null ? B.next : headA;
}
return A;
}
}
142. 环形链表 II
题目链接: 环形链表 II
具体思路可以看卡哥文章,很清晰。
要判断是否成环。这里采用快慢指针的思路,满指针走一步,快指针走两步,看是否会相遇。
成环之后,要返回进入环的位置。可以先找到相遇点位置,让一个指针从头结点开始走,另一个指针从相遇点开始走,最后一定相遇,且相遇的地方就是环入口。
/**
* 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 (true) {
if (fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
//一个从头结点出发,一个从相遇点出发。总会相遇
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
/*
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
ListNode index1 = fast;
ListNode index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
*/
}
}