文章目录
1. 合并两个有序链表(简单)
地址: https://leetcode-cn.com/problems/merge-two-sorted-lists/ss
2021/11/23
做题反思:第三次做了,思路清晰很多,但仍有两处问题
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
/**
*2021/11/23
*注意此处 dummy 的创建方式
*错误写法
*ListNode dummy = null;
*ListNode p = dummy;
*/
ListNode dummy = new ListNode(-1), p = dummy;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
p.next = l1;
l1 = l1.next;
}else {
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
/**2021/11/23
*此处用 if 判断即可, 不是用 while -> 超时
*/
if (l1 != null) {
p.next = l1;
}
if (l2 != null) {
p.next = l2;
}
return dummy.next;
}
}
2. 合并 K 个升序链表(困难)
地址:https://leetcode-cn.com/problems/merge-k-sorted-lists/submissions/
2021/11/23
做题反思:
- 思路能想到优先队列,但是实现过程没想通; -> 思考了10分钟,最终再次看答案学习解法
- 第三次:看答案后写出,弄懂并复习了之前有些不清楚及模糊的知识点
期待下次ac
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
ListNode dummy = new ListNode(-1), p = dummy;
// 泛型 https://blog.csdn.net/weixin_46644403/article/details/120945530
// 优先队列 https://labuladong.gitee.io/algo/2/20/50/
PriorityQueue<ListNode> pq = new PriorityQueue<>(
// lambda 表达式 https://blog.csdn.net/weixin_46644403/article/details/120688915
(a,b) -> a.val - b.val
);
for (ListNode head : lists) {
if (head != null) {
pq.add(head);
}
}
while (!pq.isEmpty()) {
// poll() https://www.runoob.com/java/data-queue.html
ListNode node = pq.poll();
p.next = node;
if (node.next != null) {
pq.add(node.next);
}
p = p.next;
}
return dummy.next;
}
}
复杂度:O(NlogK)
3. 环形链表(简单)
地址:https://leetcode-cn.com/problems/linked-list-cycle/
2021/11/24
ac
public class Solution {
public boolean hasCycle(ListNode head) {
/**
ListNode slow, fast;
slow = fast = head;
*/
ListNode slow = head, fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (fast == slow) {
return true;
}
}
return false;
}
}
4. 环形链表 II (中等)
地址:https://leetcode-cn.com/problems/linked-list-cycle-ii/
2021/11/24
做题反思:无环条件遗漏
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
// 判断无环
if (fast == null || fast.next == null) {
return null;
}
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
}
5. 链表的中间结点(简单)
地址:https://leetcode-cn.com/problems/middle-of-the-linked-list/
2021/11/24
AC
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
需要注意的是,如果链表长度为偶数,也就是说中点有两个的时候,我们这个解法返回的节点是靠后的那个节点。
6. 相交链表(简单)
地址:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
2021/11/24
做题反思:知道拼接 但是实现时 -> TLE:Time Limit Exceeded
又一次超时 :此处造成了无限循环
正解
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA, p2 = headB;
while (p1 != p2) {
if (p1 != null) {
p1 = p1.next;
}else {
p1 = headB;
}
if (p2 != null) {
p2 = p2.next;
}else {
p2 = headA;
}
}
return p1;
}
}
7. 删除链表的倒数第 N 个结点(中等)
地址:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
2021/11/24
做题反思:
- 应分两步: 查找到第 N 个结点 再 删除 (两个方法)
- 在一个方法中写时,逻辑关系捋不清
错误代码
2021/11/25
做题反思:
- 应返回 dummy 的倒数第 n+1 个结点, 因为 dummy 虽然比原链表长, 但是倒数时却是一样的。
- 不过注意我们又使用了虚拟头结点的技巧,也是为了防止出现空指针的情况,比如说链表总共有 5 个节点,题目就让你删除倒数第 5 个节点,也就是第一个节点,那按照算法逻辑,应该首先找到倒数第 6 个节点。但第一个节点前面已经没有节点了,这就会出错。
但有了我们虚拟节点 dummy 的存在,就避免了这个问题,能够对这种情况进行正确的删除。
正确解法:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 虚拟头结点
ListNode dummy = new ListNode(-1);
dummy.next = head;
// 代码规范: n + 1
ListNode node = findN(dummy, n + 1);
node.next = node.next.next;
// 应返回 dummy.next 而非 head
return dummy.next;
}
// 有无 public 均可, 方法名写成:findFromEnd 表达更准确
ListNode findN(ListNode head, int n) {
ListNode fast = head, slow = head;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}