代码随想录算法训练营第四天|24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交 , 142.环形链表II
Posted Smartisan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码随想录算法训练营第四天|24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交 , 142.环形链表II相关的知识,希望对你有一定的参考价值。
24. 两两交换链表中的节点
个人感觉这个不太难,刚开始打算用步进值为2,来搞,但是没有想到链表应该是怎么样的,
原来可以直接用:
cur = cur->next->next
学到了,这是我自己写的代码:
ListNode* MyLinkedList::swapPairs(ListNode* head) ListNode* dummyHead = new ListNode(); dummyHead->next = head; auto* cur = dummyHead; int idx = 0; while (cur->next != nullptr) if (idx % 2 == 0 && cur->next->next !=nullptr) auto* first = cur->next; auto* second = cur->next->next; first->next = second->next; second->next = first; cur->next = second; idx++; cur = cur->next; return dummyHead->next;
代码随想录算法训练营第四天 | 24.两两交换链表中的节点19.删除链表的倒数第N个节点160.相交链表142.环形链表II
两两交换链表中的节点
// 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)
/*
* 思路:模拟法
* 先加上虚拟结点,然后每三个步骤交换指针
*
* 三个步骤相当于两两交换结点
*
* 参考:
* https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE
* %E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html#_24-%E4%B8%A4%E4%B8%A4%E4%
* BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9
*
*/
// 加上虚拟头结点
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// 初始化三个指针,分别指向三个步骤中的第一、二、三、四个结点
// cur永远指向第一个结点
// 因为移动三次指针,所以要考虑四个结点(实际只交换firstNode和secondNode)
ListNode cur = dummyNode;
ListNode firstNode;
ListNode secondNode;
ListNode thirdNode; // 相当于剩下还没做交换的链表的头结点
// 循环三个步骤,最终得到交换结点的链表
// 循环条件不加cur.next.next.next != null因为只要交换cur后两个结点,确保后两个在就行
while (cur.next != null && cur.next.next != null)
firstNode = cur.next;
secondNode = cur.next.next;
thirdNode = cur.next.next.next;
// 三个步骤(交换fistNode和secondNode)
// 交换后,firstNode在thirdNode前面,让cur指向firstNode,下次循环交换cur.next和cur.next.next
cur.next = secondNode;
secondNode.next = firstNode;
firstNode.next = thirdNode;
// cur移动,准备下一轮交换(cur相当于头结点,是cur后面两个结点交换)
cur = firstNode;
return dummyNode.next;
删除链表的倒数第N个节点
// 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)
/*
* 思路:快慢双指针
*
* 参考:
* https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html#%E6%80%9D%E8%B7%AF
*
* 1、快指针先从虚拟头结点处先走n+1步。(n是链表倒数第n个结点)
* 2、然后快指针和慢指针同时一块走,当快指针走到最后一个结点时,慢指针就停在了倒数第n+1个结点处。
* 3、因为要删除一个结点,必须知道它的前一个结点,所以慢指针停在倒数第n+1个结点而不是倒数第n个结点处。
*
*/
// 设置虚拟头结点
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// 快慢双指针
ListNode fastNode = dummyNode;
ListNode slowNode = dummyNode;
// 快指针优先移动到第n+1个结点处(虚拟头结点不算)
for (int i = 0; i < n; i++)
fastNode = fastNode.next;
// 然后慢指针和快指针同时移动
// 当快指针停到链表最后一个结点时,慢指针停在倒数第n+1个结点处
while (fastNode.next != null)
slowNode = slowNode.next;
fastNode = fastNode.next;
// 删除倒数第n个结点
slowNode.next=slowNode.next.next;
return dummyNode.next;
相交链表
// class ListNode
// int val;
// ListNode next;
// ListNode(int x)
// val = x;
// next = null;
//
//
public class Solution
public ListNode getIntersectionNode(ListNode headA, ListNode headB)
/*
* 思路:双指针
*
* 参考:
* https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%
* A8%E7%9B%B8%E4%BA%A4.html#%E6%80%9D%E8%B7%AF
*
* 本题求两个链表交点节点的指针。 这里要注意,交点不是数值相等,而是指针相等。
* 1、curA指向链表A的头结点,curB指向链表B的头结点。
* 2、求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB末尾对齐的位置。
* 3、就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到交点。
* 4、否则返回null。
*
*/
ListNode curA = headA;
ListNode curB = headB;
// 获得两链表的长度
int lenA = 0; // 链表A的长度
int lenB = 0; // 链表B的长度
// 遍历链表的循环条件,是node!=null还是node.next!=null
// 取决于你想让node指针最终停留在链表哪个位置
// 如果是停留在最后一个结点处,那么node.next!=null(一定要注意确保当前结点不为空)
// 如果是停留在链表结尾处的null,那么node!=null
while (curA != null)
lenA++;
curA = curA.next;
while (curB != null)
lenB++;
curB = curB.next;
// 设置链表较长的那个为链表A,另一个为链表B,这是为了统一后面的操作
if (lenA < lenB)
// 交换长度
int lenTmp = lenA;
lenA = lenB;
lenB = lenTmp;
// 交换链表
ListNode tmpNode = headA;
headA = headB;
headB = tmpNode;
// curA,curB重新指向两链表第一个结点
curA = headA;
curB = headB;
// 求出两链表长度差值,然后让curA从头移动到两链表末尾对齐时,curB的位置
// (链表A上倒数第lenB个结点)
int diff = lenA - lenB;
while (diff > 0)
diff--;
curA = curA.next;
// curA,curB同时移动,直到两指针指向同一个结点处,如果没有则返回null
while (curA != null)
if (curA == curB)
return curA;
curA = curA.next;
curB = curB.next;
return null;
环形链表II
// class ListNode
// int val;
// ListNode next;
// ListNode(int x)
// val = x;
// next = null;
//
//
public class Solution
public ListNode detectCycle(ListNode head)
/*
* 思路:快慢指针
*
* 设置一个快指针和一个慢指针,快指针的速度是慢指针的两倍。
* 最开始快慢指针同时从head结点开始遍历,如果链表有环,那么最终快指针一定会在环中和
* 慢指针相遇,此时,从相遇点处到环形入口点处的距离=从头结点到环形入口点处的距离。
* 再设置两指针,一个指向相遇点,一个指向链表头结点,同时遍历就能到达环形入口点处。
*
* 公式证明参考:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II
* .html#%E6%80%9D%E8%B7%AF
*
*/
ListNode slowNode = head;
ListNode fastNode = head;
while (fastNode != null && fastNode.next != null)
slowNode = slowNode.next;
fastNode = fastNode.next.next;
// 快慢指针相遇,找到相遇点
if (slowNode == fastNode)
// 从相遇点处到环形入口点处的距离=从头结点到环形入口点处的距离
ListNode p1 = fastNode;
ListNode p2 = head;
// 从head和相遇点,同时查找直至相遇,即环形入口点处
while (p1 != p2)
p1 = p1.next;
p2 = p2.next;
return p1; // 环形入口点处
return null;
以上是关于代码随想录算法训练营第四天|24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交 , 142.环形链表II的主要内容,如果未能解决你的问题,请参考以下文章
算法leetcode|24. 两两交换链表中的节点(rust重拳出击)