24. 两两交换链表中的节点leetcode地址
自己写的0指2,1指3,然后2再指1,这样可以少一个中间量
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
while(cur.next != null && cur.next.next != null){
ListNode node = cur.next;
cur.next = cur.next.next;
node.next = cur.next.next;
cur.next.next = node;
cur = cur.next.next;
}
return dummy.next;
}
}
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head); // 用哨兵节点简化代码逻辑
ListNode node0 = dummy;
ListNode node1 = head;
while (node1 != null && node1.next != null) { // 至少有两个节点
ListNode node2 = node1.next;
ListNode node3 = node2.next;
node0.next = node2; // 0 -> 2
node2.next = node1; // 2 -> 1
node1.next = node3; // 1 -> 3
node0 = node1; // 下一轮交换,0 是 1
node1 = node3; // 下一轮交换,1 是 3
}
return dummy.next; // 返回新链表的头节点
}
}
差灵山爱抚的题解这样写,这样所有节点都变变量表示更加清晰,值得学习
感谢爱抚,欢迎关注 B站@灵茶山艾府
19.删除链表的倒数第N个节点 leetcode地址
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
ListNode right = dummy;
ListNode left = dummy;
dummy.next = head;
while(n-- > 0){
right = right.next;
}
while(right.next != null){
left = left.next;
right = right.next;
}
left.next = left.next.next;
return dummy.next;
}
}
快慢指针,如果先遍历算长度size,在遍历size-n,是两层
如果用快慢指针,让右指针先动n,再左右一起动,把后n转换成前n
代码参考了爱抚大人,爱抚大人的编码风格真的爱了,写的简直太漂亮了,想谈
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 由于可能会删除链表头部,用哨兵节点简化代码
ListNode dummy = new ListNode(0, head);
ListNode left = dummy, right = dummy;
while (n-- > 0) {
right = right.next; // 右指针先向右走 n 步
}
while (right.next != null) {
left = left.next;
right = right.next; // 左右指针一起走
}
left.next = left.next.next; // 左指针的下一个节点就是倒数第 n 个节点
return dummy.next;
}
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/solutions/2004057/ru-he-shan-chu-jie-dian-liu-fen-zhong-ga-xpfs/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
160.链表相交leetcode地址
(版本一)先行移动长链表实现同步移动
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while (curA != null) { // 求链表A的长度
lenA++;
curA = curA.next;
}
while (curB != null) { // 求链表B的长度
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap-- > 0) {
curA = curA.next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
(版本二) 合并链表实现同步移动
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
// p1 指向 A 链表头结点,p2 指向 B 链表头结点
ListNode p1 = headA, p2 = headB;
while (p1 != p2) {
// p1 走一步,如果走到 A 链表末尾,转到 B 链表
if (p1 == null) p1 = headB;
else p1 = p1.next;
// p2 走一步,如果走到 B 链表末尾,转到 A 链表
if (p2 == null) p2 = headA;
else p2 = p2.next;
}
return p1;
}
}
方法一先把B移动到跟A末尾对齐,再找相同的,
方法二很巧妙,如果有相同的,那走都过两边A+B的路程是一样的
142.环形链表II leetcode地址
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode first = head;
ListNode slow = head;
while(first != null && first.next != null){
first = first.next.next;
slow = slow.next;
if(first == slow){
while(first != head){
first = first.next;
head = head.next;
}
return first;
}
}
return null;
}
}
快指针两步两步的跳,所以进入循环的条件是,快指针和快指针的下个不为空。