LeetCode 24. 两两交换链表中的节点
题目链接:24. 两两交换链表中的节点
解题思路
思路一(虚拟头节点)
解题思路如下图:
代码实现:
/**
* 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 pre;
pre = head;
ListNode humNode = new ListNode(-1);
humNode.next = pre;
ListNode cru = humNode;
if(pre == null){
return head;
}
while(pre != null && pre.next != null){
ListNode temp = pre.next;
ListNode temp1 = temp.next;
cru.next = temp;
temp.next = pre;
pre.next = temp1;
cru = pre;
pre = temp1;
}
return humNode.next;
}
}
注意:
1.链表中最为重要的解题要点,我们不能直接用链表指针进行修改,我应该创建一个指针去代替链表指针去修改链表。
2.在进行指针移动的时候,需要注意cru,pre会移动到哪个节点上。
3.对于特殊的基数节点我们可以将while写为(pre != null && pre.next != null)
4.在虚拟头节点算法中输出链表时,应该排除虚拟头节点(humNode.next)。
LeetCode 19.删除链表的倒数第N个节点
题目链接:19.删除链表的倒数第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) {
int sz = 0;
ListNode pre = head;
while(pre != null){
pre = pre.next;
sz++;
}
if(sz - n == 0 || sz == 1){
return head.next;
}
ListNode cur = head;
for(int i = 0; i < sz - n - 1; i++){
cur = cur.next;
}
cur.next = cur.next.next;
return head;
}
}
思路二(双指针)
我们将使用两指针(fast,slow),我们可以模拟倒数n,首先先让fast和slow距离n,当slow指针移动到最后一个节点,fastz指针则为倒数n的前一个节点。
注意:
1.图中slow.next指向fast只是这道题的巧合,实际是slow.next = slow.next.next。
2.使用虚拟节点是防止,链表中只有一个值时,fast.next报错(fast为null)。
/**
* 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 Humhead = new ListNode(-1);
Humhead.next = head;
ListNode fast = Humhead;
ListNode slow = Humhead;
for(int i = 0; i < n; i++){
fast = fast.next;
}
while(fast.next != null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return Humhead.next;
}
}
LeetCode 面试题 02.07. 链表相交
题目链接:面试题 02.07. 链表相交
解题思路
思路一
分析题目可得:
1. 链表是不会在分叉的,因为链表节点只会存一个指针
我先将两个链表进行遍历,求出长度为后面头结点对其做准备
我们将两个链表的头节点对其,再遍历如果指针相等就输出节点,如果不相等,两个头节点往后移一位
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode cur = headA;
ListNode pre = headB;
int ALen = 0;
int BLen = 0;
//求headA的长度
while(cur != null){
cur = cur.next;
ALen++;
}
//求headB的长度
while(pre != null){
pre = pre.next;
BLen++;
}
cur = headA;
pre = headB;
//如果cur长度小于pre长度,我们将长度大变成cur,为了节省代码,可以不用单独写cur长度小于pre长度的实现函数
if(BLen > ALen){
int temp = ALen;
ALen = BLen;
BLen = temp;
ListNode tempNode = cur;
cur = pre;
pre = tempNode;
}
int len = ALen - BLen;
while(len > 0){
cur = cur.next;
len--;
}
//找出相交的节点
while(cur != null){
if(cur == pre){
return cur;
}
cur = cur.next;
pre = pre.next;
}
return null;
}
}
LeetCode 142.环形链表II
题目链接:142.环形链表II
解题思路
思路一(快慢双指针)
我们假设fast的速度时slow的两倍,相遇时2(x+y) = x+y+n(z+y),化简可得x=(n-1)(z+y)+z,从这个公式可得,如果以相同的速度,一个从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){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
ListNode index1 = fast;
ListNode index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
疑虑点:为什么慢指针与快指针相遇,慢指针还没走完一圈环?
快指针比慢指针速度快,慢指针在跑第一圈的时候,假设快指针没有相遇,并且快指针就在慢指针前面很短的距离(忽略不计),慢指针已经跑玩一圈(一圈常为x)的时候才追上,快指针的需要跑了 2x,才能重新追上,但是一圈只有x,如何在不经过慢指针的情况下,跑两圈,显然假设就不成立
总结
1.涉及到修改链表时,需要使用虚拟头节点(另外:如果头节点修改时不会面临空指针报错可以不用使用虚拟头节点(206.反转链表))。
2.链表是不会在分叉的,因为链表节点只会存一个指针
3.第四题等同于一道数学题(涉及追及问题(不懂的话可以观看:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点))