LeetCode:24_两两交换链表中的节点
问题描述
解决方案:
1.思路
- 最先想到的是递归实现
- 递归的返回值和参数分别是:新链表的头节点和原始链表的头结点;
- 递归的终止条件是:链表中没有节点 ( h e a d = = n u l l 而且 h e a d . n e x t = = n u l l ) (head == null 而且head.next == null) (head==null而且head.next==null)或者链表中只有一个节点 ( h e a d = = n u l l ) (head == null) (head==null);
- 递归的逻辑是:假如链表有6个节点,那么题目中的函数swapPairs(ListNode head)的含义就是按照题目要求两两交换该链表中的节点;所以直接:head指向紫色范围的子链表【swapPairs(newHead.next)】;newHead.next=head; 返回newHead;
2.代码实现
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
}
3.复杂度分析
4.注意
- 递归的逻辑最好去画画图;
LeetCode: 19_删除链表的倒数第N个节点
解决方案:
1.思路:
- 首先遍历一遍链表,然后计算倒数第n个节点的索引值,进行正常删除,但是时间复杂度就为 O ( n ) O(n) O(n);
- 也可以通过栈实现,将链表元素全部入栈,在弹出栈的过程中,弹出的第n个元素就是要删除的节点,那么栈顶的元素就是待删除链表元素的前驱节点。
- 双指针,设置两个快慢指针,快指针比慢指针提前n个节点,那么当快指针遍历到链表结尾的时候,慢指针指的就是倒数第N个节点
2.代码实现
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0, head);
ListNode slow = dummyHead;
ListNode fast = head;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
slow.next= slow.next.next;
ListNode ans =dummyHead.next;
return ans;
}
}
3.复杂度分析
4.注意事项
- 考虑到我们删除某一个链表节点,需要首先找到它的前驱结点,所以,我们可以设置一个哑结点作为头结点,让慢指针从哑结点开始遍历,其余规则不变,那么当快指针遍历到链表结尾的时候,慢指针指的就是倒数第N个节点的前驱节点,直接进行删除就好。
LeetCode: 面试题 02.07. 链表相交
解决方案:
1.思路:使用双指针
-
- 参考:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/solutions/1/mian-shi-ti-0207-lian-biao-xiang-jiao-sh-b8hn/
2.代码实现
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA == null ? headB : pA.next;
pB = pB == null ? headA : pB.next;
}
return pA;
}
}
3.复杂度分析
4.注意事项
- 注意三元条件运算符大大精简了代码量;
- 其基本语法为:条件 ? 表达式1 : 表达式2。如果条件为真(true),则计算并返回表达式1的值;如果条件为假(false),则计算并返回表达式2的值。
-
LeetCode: 142_环形链表II
-
解决方案:
1.思路:
方法一:哈希表
- 遍历链表中的每个节点,并将它记录下来,存入哈希表中;
- 一旦遇到了此前遍历过的节点,就可以判定链表中存在环。
方法二:快慢指针
- 使用快慢指针,起始都位于链表的头部,开始移动
- 慢指针每次向后移动一个位置(slow = slow.next;),而快指针向后移动两个位置( fast = fast.next.next;)。
- 如果链表中存在环,则两指针将再次相遇(fast == slow);
- 再额外使用一个指针 ptr,起始,它指向链表头部ListNode ptr = head;;随后,它和慢指针每次向后移动一个位置ptr = ptr.next; slow = slow.next。最终,它们会在入环点相遇,返回ptr即可。
2.代码实现
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
}