复杂链表的复制
- 题目:就是一个链表,不仅指向自己后继节点,还有一个随机指针,随机指向一个节点,可能是null.
- 解决思路:分三步走:
- 完成链表节点的复制,只是单纯的复制 A->B->C->D->E变成A->A'->B->B'->C->C'->D->D'->E->E' 所以每次都需要新建一个节点插入原链表中
- 完成刚刚复制新加节点中的随机指针的复制(需要判断原来的节点是不是有随机指针)
- 拆分节点,把节点一分为二,返回复制后的节点即可。
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return head;
Node cur = head;
//简单复制节点,插入原链表中
while (cur != null) {
Node copy = new Node(cur.val);
copy.next = cur.next;
cur.next = copy;
cur = cur.next.next;
}
//新增节点随机指针的复制,需要注意对原生节点的随机指针的判断
cur = head;
while (cur != null) {
if (cur.random != null) {
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
//对链表进行拆分
cur = head;
Node tmp = head.next;
Node copyNode = head.next;
while (cur != null) {
cur.next = cur.next.next;
cur = cur.next;
if (tmp.next != null) {
tmp.next = tmp.next.next;
tmp = tmp.next;
}
}
return copyNode;
}
}
两个链表的第一个公共节点
- 思路就是:两个链表从头开始一起往前走,不断后移不断后移,走完自己本身的链表之后,接另一个链表的头节点,继续走,这样一次两个链表如果有相同的节点就会相遇。如果没有,就设置循环条件判定,返回null。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
if (headA == null || headB == null) return null;
int count = 0;
while (curA != curB) {
if (curA.next != null) {
curA = curA.next;
} else {
curA = headB;
count++;
}
if (curB.next != null) {
curB = curB.next;
} else {
curB = headA;
count++;
}
if (count > 2) return null;
}
return curA;
}
}
反转链表
要求:输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
- 采用原地替换的方法。一个往前走,一个记录当前节点,将二者连接起来。先记录当前节点的下一个节点tmp=cur.next;,然后将当前节点的下一个节点指向前一个节点cur.next=pre,然后原本代表前一个节点的pre此时已经和cur建立连接,所以可以将其后移pre=cur;,当前节点自然也要后移cur=tmp;.
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode cur = head;
ListNode pre = null;
ListNode tmp = null;
while (cur != null) {
tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
链表中倒数第k个节点
- 自己的做法是用栈压,然后弹出,也还行。
- 推荐做法是双指针,都从头结点开始,一个先走,一个后走,两个指针之间保持的距离是(k-1)
- 当先走的指针指向null时,输出后走的指针所指向的节点。
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode former = head;
ListNode latter = head;
for (int i = 0; i < k; i++) {
if (former == null) return null;
former = former.next;
}
while (former != null) {
former = former.next;
latter = latter.next;
}
return latter;
}
}
删除链表的节点
- 分两步走:定位节点+修改引用
- 定位节点:遍历,直到head.val == val
- 修改引用:节点cur的前驱节点为pre,后继节点为cur.next,只需要执行pre.next = cur.next即可达到删除cur节点的功能。
- 特例:若需要删除的是头节点,则直接返回head.next
- 实现过程:
- 特例处理
- 初始化:pre = head; cur = head.next;
- 定位节点:cur为空或值相等时结束
- 删除节点
- 代码:
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head.val == val) return head.next;
ListNode pre = head;
ListNode cur = head.next;
while (cur != null && cur.val != val) {
pre = cur;
cur = cur.next;
}
if (cur != null) pre.next = cur.next;
return head;
}
}