今日内容:24.两两交换链表中的节点,19.删除链表的倒数第N个节点,面试题02.07.链表相交,142.环形链表||,总结
代码随想录链接:代码随想录 (programmercarl.com)
24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
普通解法
- 添加一个虚拟头节点方便第一次交换。
ListNode dummy = null;
dummy.next = head;//创建虚拟头节点
- 前提是存在两个非空的节点可以交换。
while (cur.next != null && cur.next.next != null)
-
在保证链表不断的情况下修改各个节点的next,以实现交换。
- 先保存原来的点位
temp = cur.next.next.next; firstNode = cur.next; secondNode = cur.next.nxet;- 再更改指针
cur.next = secondNode; secondnode.next = firstnode; firstnode.next = temp; cur = firsrnode;//移动至下一轮
总代码如下:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(-1);
dummy.next = head;//创建虚拟头节点
ListNode cur = dummy;
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 dummy.next;
}
}
递归解法
用递归函数去返回每一组节点的头节点,代码如下:
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode next = head.next;
ListNode newNode = swapPairs(next.next);
next.next = head;
head.next = newNode;
return next;
}
}
注意:(head == null || head.next == null)中的两个判定条件的顺序不能改!
19.删除链表中的倒数第N个节点
给你一个链表,删除链表的倒数第
n**个结点,并且返回链表的头结点。
最粗暴的就是计算出size,然后找到那个节点,代码如下:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode ();
dummy.next = head;
ListNode cur = dummy;
int size = 0;
while(cur.next != null){
cur = cur.next;
size++;
}
cur = dummy;
for(int i = 0; i < size - n; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
return dummy.next;
}
}
这里创建了一个虚拟头节点dummy,比较直观的模拟了这样一个过程
时间复杂度O(n),空间复杂度O(1)
快慢指针
然后思考了一种双指针写法,一个指针在前,另一个指针在后,两个指针中间相隔n+1个距离,最开始快指针先跑,跑一步然后n--,当n减到0后,两个指针一起跑,直到快指针跑到头,这个时候让左指针删掉下一个节点即可。
代码如下:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode ();
dummy.next = head;
ListNode left = dummy;
ListNode right = new ListNode();
right = dummy;
while(right.next != null ){
right = right.next;
n--;
if(n < 0 ){
left = left.next;
}
}
left.next = left.next.next;
return dummy.next;
}
}
时间复杂度O(n),空间复杂度O(1) 这次竟然一遍过了啊啊啊啊,激动的嘞,虚拟头节点确实好用,临界条件的判断舒服了好多。 这题应该算比较简单,能够自己写出两个方法并跑通。
面试题 02.07.链表相交
给你两个单链表的头节点
headA和headB,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回null。 图示两个链表在节点c1开始相交 :题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后,链表必须 保持其原始结构 。
因为这题是找交点,所以如果有交点,那么这两个列表在尾部会有一段是相同的,那么只要先把这两段“对齐”,就可以找到交点。
如何对齐呢?我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:
代码如下:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while(curA != null){
curA = curA.next;
lenA++;
}
while(curB != null){
curB = curB.next;
lenB++;
}
curA = headA;
curB = headB;
if (lenB > lenA) {
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
int n = lenA - lenB;
while(n-- > 0){
curA = curA.next;
}
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
}
- 求两个链表的长度
- 找到长的链表设置为A链表,短的为B链表
- “对齐”:将长链表指针移动到和锻炼表一样的位置
- 一起移动两个指针,找到节点相同的点然后返回该点,若没有则返回null
就是中间这一段选出长的列表作为A链表,短的链表作为B链表,有没有更好的写法。
环形链表 ||
给定一个链表的头节点
head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。 如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos是-1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。 不允许修改 链表。
看到了快慢指针法,让有环的话就会在环中相遇,尝试写一下代码:
卡在了数学,不过看懂了! 代码如下:
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = 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;
}
}
让slow碰到fast能证明有环,通过数学公式x = (n-1)*(z+y)+z
,如图所示:
可以得到结论:从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
结束,今天的学习有全靠自己撸出来的代码,也有全靠答案的,最后一个环形链表真的精彩绝伦,拍案叫好。爽!