24. 两两交换链表中的节点
注意画图及需要定义几个节点,这里是需要临时节点的,因为节点的指针发生转向了,需要保存下一个节点,进行指针的变向。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy; //pre指向当前节点的前一个节点
ListNode cur = head; //cur指向第一个节点
ListNode temp; //记录临时节点,cur的下一个节点,因为要两两交换
//注意判断两两交换的条件,要cur不为null,且cur的下一个节点也不为null
//若为奇数个节点,就无法两两交换了
while(cur != null&&cur.next != null){
temp = cur.next;
cur.next = temp.next; //步骤一
temp.next = cur; //步骤二
pre.next = temp; //步骤三
//指向下一轮节点
pre = cur;
cur = cur.next;
}
return dummy.next;
}
}
19.删除链表的倒数第N个节点
这里对slow和fast的指向要理解后应用,不然容易乱写。
注意 fast最终要指向null才会结束。
/*
法一:遍历整个链表,计算节点总数,再去删除倒数第n个节点
法二:双指针法,设置虚拟头节点,力扣官网题解讲的比较详细。当 fast 遍历到链表的末尾(fast 为空指针)时,slow 恰好指向倒数第 n 个节点。
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
//一般为fast和slow同时指向head,则最终slow指向倒数第n个节点,若指向虚拟头节点,则最终为倒数第n+1个节点,即n的前驱节点
ListNode slow = dummy;
//指向头节点
ListNode fast = head;
//比slow要超前n个节点,
for(int i = 0;i < n;i++)
fast = fast.next;
//注意fast最后要到null才结束
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
02.07. 链表相交
比较基础,思路想到了就能写出来,对节点的命名要记住,尽量有意义地去命名
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0,lenB = 0,gapAB = 0;
//求链表A的长度
while(curA != null){
curA = curA.next;
lenA++;
}
//求链表B的长度
while(curB != null){
curB = curB.next;
lenB++;
}
//这里要使指针重新指向头节点,不然没进iF判断的话,curA和curB指向的都是最后一个节点
curA = headA;
curB = headB;
//使curA始终指向的是最长链表的头,lenA是其长度,注意长度和节点都要交换
if(lenA < lenB){
int temp;
//swap(lenA,lenB)
temp = lenA;
lenA = lenB;
lenB = temp;
//swap(curA,curB)
curA = headB;
curB = headA;
}
gapAB = lenA-lenB; //求链表A和B的长度差
//使curA和curB在同一起点上
for(int i = 0;i < gapAB;i++)
curA = curA.next;
//遍历两个链表,遇到相同则直接返回
while(curA != null){
if(curA == curB)
return curA;
curA = curA.next;
curB = curB.next;
}
return null;
}
}
142.环形链表II
这类链表题目一般都用双指针法解决,如寻找距离尾部第 K
个节点、寻找环入口、寻找公共尾部入口等。
双指针法
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
//注意fast的后继指针也要判断一下是否为null,因为fast一次走两步
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){ //说明有环
ListNode index1 = head;
ListNode index2 = fast;
//两个指针分别指向头节点和相遇节点,每次走一步,相遇处即为入口
//用特值法可判断出来
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
哈希表法
//思路:将节点存储在哈希表中,如果哈希表中已存在该节点,说明链表中存在环,且该节点就是入口,否则说明链表中无环。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode pos = head;
Set<ListNode> visited = new HashSet<ListNode>();
while(pos != null){
// 判断哈希表中是否有该节点,有则表明是入口,直接返回该节点,若没有则将该节点加入哈希表中
if(visited.contains(pos))
return pos;
else
visited.add(pos);
pos = pos.next; //指向下一节点
}
return null;
}
}