目录
题目一:移除链表元素
(1)题目链接
(2)题目要求
(3)题解
题目二:反转链表
(1)题目链接
(2)题目要求编辑
(3)题解
题目三:链表的中间节点
(1)题目链接
(2)题目要求
题目四:返回倒数第k个节点
(1)题目链接
(2)题目要求
(3)题解
题目五:合并两个有序链表
(1)题目链接
(2)题目要求
(3)题解
题目一:移除链表元素
(1)题目链接
移除链表元素https://leetcode.cn/problems/remove-linked-list-elements/description/
(2)题目要求
(3)题解
操作:
cur代表当前需要删除的节点
prev代表当前需要删除节点cur的前驱节点
如果找到需要删除的节点,prev.next = cur.next;cur = cur.next;
如果没找到所要删除的节点,移动prev节点prev = cur;再移动cur判断下一个节点cur = cur.next;
最后的效果
如何处理头节点就是要删除的节点的情况?
先将头节点以外的删除再来考虑头节点位置即可
if(head.val == val) {
head = head.next;
}
也可先考虑头节点的情况,while循环判断
public void removeAllKey(int val) {//1. 判空if (head == null) {head = head.next;}//2. 定义prev 和 curListNode prev = head;ListNode cur = head.next;//3.开始判断并且删除while (cur != null) {if (cur.val == val) {//找到了prev.next = cur.next;} else {prev = cur;}cur = cur.next;}//4.处理头节点if(head.val == val) {head = head.next;}}
public ListNode removeElements(ListNode head, int val) { // 1. 处理头节点 while (head != null && head.val == val) { head = head.next; } // 2. 如果链表为空,直接返回 if (head == null) { return head; } ListNode cur = head; // 3. 开始判断并且删除 while (cur.next != null) { if (cur.next.val == val) { // 找到了 ListNode del = cur.next; cur.next = del.next; } else { cur = cur.next; } } // 4. 这里不需要再处理头节点,因为在循环开始前已经处理过了 return head; }
题目二:反转链表
(1)题目链接
反转链表https://leetcode.cn/problems/reverse-linked-list/description/
(2)题目要求
(3)题解
思路:
- 采用头插法,将头节点以外的节点依次插入到头节点前面并改变next的指向
操作:
- 首先我们判断头节点head为空的情况,为空时返回head即可
- cur节点表示什么?定义一个cur节点表示头结点的下一个节点,表示我们从头节点的下一个节点开始进行头插
- curN节点表示什么?curN节点表示记录cur的下一个节点,当我们头插一个节点之后为了不丢失下一个结点的地址,我们需要提前记录下这个节点的地址,以便进行下一次头插
- 在进行一次头插后我们就改变头节点head的位置,同时cur向后移动进行下一次头插
public ListNode reverseList(ListNode head) {if (head == null) {return head;}ListNode cur = head.next;head.next = null;while (cur != null) {ListNode curN = cur.next;cur.next = head;head = cur;cur = curN;}return head;}
题目三:链表的中间节点
(1)题目链接
链表的中间节点https://leetcode.cn/problems/middle-of-the-linked-list/description/
(2)题目要求
(3)题解
寻找中间节点用到了非常经典的快慢指针方法
思路:
使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。
这道题换一种说法其实就是简单的数学问题,有两个人,fast和slow,fast的速度是2,slow的速度是1,它们从起点同时出发,当fast到达终点时,slow就在路程的中点,而slow所在的位置就是我们要返回的中间节点
操作:
- fast和slow在同一起点,也就是head
- 循环条件是什么?
这里我们要考虑到奇数节点和偶数节点的区别
当链表的节点数为偶数时,fast == null时找到中间节点停止循环
当链表的节点数为奇数时,fast.next == null时找到中间节点停止循环
public ListNode middleNode(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {ListNode tmp = fast.next;fast = tmp.next;slow = slow.next;}return slow;}
题目四:返回倒数第k个节点
(1)题目链接
返回倒数第k个节点https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/description/
(2)题目要求
(3)题解
思路:
因为题目要求是返回导数第k个节点,在这里我们依然使用的是快慢指针方法
我们先让fast走k步,来抵消倒数的这个差值,然后再让fast和slow同时走
操作:
- fast和slow从同一起点head出发
- 先将fast走k步再让它们同时走,直到fast为空时返回slow即可
public int kthToLast(ListNode head, int k) {ListNode fast = head;ListNode slow = head;for(int i = 0;i < k;i++) {fast = fast.next;}while(fast != null) {fast = fast.next;slow = slow.next;}return slow.val;}
题目五:合并两个有序链表
(1)题目链接
合并两个有序链表https://leetcode.cn/problems/merge-two-sorted-lists/description/
(2)题目要求
(3)题解
思路:
- 将两个链表的头节点依次进行比较,如果headA.val < headB.val,则tmp.next = headA,让headA往后走一步,tmp也往后走一步;headA.val > headB.val同理
- 如果A链表或B链表中有一个提前遍历完,那么再往后走就指null,这时tmp.next及时接上那个未遍历完的链表节点。
操作:
- 创建一个傀儡节点,用来指向两个链表头节点较小的一个
- 循环条件是什么?在两个链表的长度长度不同时,我们需要当一个链表判断完时接上另一个链表,这时我们要确保短的链表每个节点的val都判断到,也就是两个链表的不能为null,也就是headA != null && headB != null
- 要考虑两个链表空的情况,当A为空时直接指向B即可,否则相反
public ListNode mergeTwoLists(ListNode headA, ListNode headB) {ListNode newH = new ListNode();ListNode tmp = newH;while(headA != null && headB != null) {if(headA.val < headB.val) {tmp.next = headA;headA = headA.next;tmp = tmp.next;} else{tmp.next = headB;headB = headB.next;tmp = tmp.next;}}if(headA != null) {tmp.next = headA;} else {tmp.next = headB;}return newH.next;}