目录
八、 链表
57. 环形链表 ① ×
58. 两数相加 ② √
59. 合并两个有序链表 ① √-
60. 随机链表的复制 ②
61. 反转链表II ② ×
62. K个一组翻转链表 ③
63. 删除链表的倒数第N个结点 ② √-
64. 删除排序链表中的重复元素II ② √-
65. 旋转链表 ② √-
66. 分隔链表 ② √
67. LRU缓存 ②
八、 链表
57. 环形链表 ① ×
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引 。
进阶:你能用 O(1)
(即,常量)内存解决此问题吗?
力扣解析:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
方法2:(0ms)
public boolean hasCycle(ListNode head) {if (head == null || head.next == null) return false;int n = 10010;while (n -- > 0) {head = head.next;if (head == null) return false;}return true;}
58. 两数相加 ② √
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0] 输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]
提示:
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
方法1:(1ms)
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode head = new ListNode();ListNode temp = head;int more = 0;int res = 0;while (!(l1 == null && l2 == null)){res = (l1 != null? l1.val : 0) + (l2 != null? l2.val : 0) + more;if (res > 9){res = res - 10;more = 1;}else {more = 0;}ListNode newNode = new ListNode(res);temp.next = newNode;temp = temp.next;if (l1.next != null){l1 = l1.next;}if (l2.next != null){l2 = l2.next;}}if (more == 1){temp.next = new ListNode(more);}return head.next;}
59. 合并两个有序链表 ① √-
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
方法1:(0ms)
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {if (list1 == null && list2 == null) {return null;} else if (list1 == null && list2 != null) {return list2;} else if (list1 != null && list2 == null) {return list1;}ListNode head = new ListNode();ListNode left = list1;ListNode right = list2;ListNode temp = head;while (left != null && right != null) {if (left.val < right.val) {temp.next = left;left = left.next;} else {temp.next = right;right = right.next;}temp = temp.next;}if (left == null) {temp.next = right;} else if (right == null) {temp.next = left;}return head.next;}
方法2:(0ms 递归)
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {if (list1 == null) {return list2;}else if (list2 == null) {return list1;}else if (list1.val < list2.val) {list1.next = mergeTwoLists(list1.next, list2);return list1;}else {list2.next = mergeTwoLists(list1, list2.next);return list2;}}
60. 随机链表的复制 ②
61. 反转链表II ② ×
给你单链表的头指针 head
和两个整数 left
和 right
,其中 left <= right
。请你反转从位置 left
到位置 right
的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1 输出:[5]
提示:
- 链表中节点数目为
n
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
方法2:(0ms)
public ListNode reverseBetween(ListNode head, int m, int n) {// 定义一个dummyHead, 方便处理ListNode dummyHead = new ListNode(0);dummyHead.next = head;// 初始化指针ListNode g = dummyHead;ListNode p = dummyHead.next;// 将指针移到相应的位置for(int step = 0; step < m - 1; step++) {g = g.next; p = p.next;}// 头插法插入节点for (int i = 0; i < n - m; i++) {ListNode removed = p.next;p.next = p.next.next;removed.next = g.next;g.next = removed;}return dummyHead.next;}作者:贾卷积
链接:https://leetcode.cn/problems/reverse-linked-list-ii/solutions/138910/java-shuang-zhi-zhen-tou-cha-fa-by-mu-yi-cheng-zho/
62. K个一组翻转链表 ③
63. 删除链表的倒数第N个结点 ② √-
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1 输出:[]
示例 3:
输入:head = [1,2], n = 1 输出:[1]
提示:
- 链表中结点的数目为
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:你能尝试使用一趟扫描实现吗?
方法1:(0ms)
public ListNode removeNthFromEnd(ListNode head, int n) {if (head.next == null && n == 1){return null;}int count = 1;ListNode temp = head;while (temp.next != null){count++;temp = temp.next;}if (n == count){return head.next;}else {int cnt = 1;temp = head;while (cnt < count - n) {cnt++;temp = temp.next;}temp.next = temp.next.next;return head;}}
方法2:(0ms)
解题思路:
整体思路是让前面的指针先移动 n 步,之后前后指针共同移动直到前面的指针到尾部为止
首先设立预先指针 pre
设预先指针 pre 的下一个节点指向 head,设前指针为 start,后指针为 end,二者都等于 pre
start 先向前移动n步
之后 start 和 end 共同向前移动,此时二者的距离为 n,当 start 到尾部时,end 的位置恰好为倒数第 n 个节点
因为要删除该节点,所以要移动到该节点的前一个才能删除,所以循环结束条件为 start.next != null
删除后返回 pre.next,为什么不直接返回 head 呢,因为 head 有可能是被删掉的点
时间复杂度:O(n)
作者:画手大鹏
链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/solutions/7803/hua-jie-suan-fa-19-shan-chu-lian-biao-de-dao-shu-d/
//通过快慢指针来解决,类似于你要删除中间元素的题public ListNode removeNthFromEnd(ListNode head, int n) {//定义一个伪节点,用于返回结果ListNode dumpy = new ListNode(0);dumpy.next = head;//定义一个快指针,指向伪节点,用于遍历链表ListNode prev = dumpy;//定一个慢指针,ListNode tail = dumpy;//让快指针先移动 n 步while(n >0){prev = prev.next;n--;}//只要快指针不指向空,就继续循环while(prev.next !=null){//让快慢指针同时移动tail = tail.next;prev = prev.next;}//这时慢指针移动到的位置就是,要删除节点的前一个节点//所以只要删除当前节点的下一个节点tail.next = tail.next.next;//返回为指针指向的头节点return dumpy.next;}
64. 删除排序链表中的重复元素II ② √-
给定一个已排序的链表的头 head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
示例 1:
输入:head = [1,2,3,3,4,4,5] 输出:[1,2,5]
示例 2:
输入:head = [1,1,1,2,3] 输出:[2,3]
提示:
- 链表中节点数目在范围
[0, 300]
内 -100 <= Node.val <= 100
- 题目数据保证链表已经按升序 排列
方法1:(0ms)
public static ListNode deleteDuplicates(ListNode head) {if (head == null || head.next == null){return head;}ListNode pre = new ListNode(0);pre.next = head;ListNode newNode = pre;while (head != null && head.next != null){if (head.val != head.next.val) { // 用值做比较,而不是两个节点做比较,节点一定不相等head = head.next;pre = pre.next;}else {while (head.next != null && head.next.val == head.val){ // 用值做比较head = head.next;}head = head.next;pre.next = head;}}return newNode.next;}
解题思路:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
65. 旋转链表 ② √-
给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。
示例 1:
输入:head = [1,2,3,4,5], k = 2 输出:[4,5,1,2,3]
示例 2:
输入:head = [0,1,2], k = 4 输出:[2,0,1]
提示:
- 链表中节点的数目在范围
[0, 500]
内 -100 <= Node.val <= 100
0 <= k <= 2 * 109
方法1:(1842ms)
public static ListNode rotateRight(ListNode head, int k) {if (head == null || head.next == null || k == 0){return head;}ListNode temp = head;ListNode pre = new ListNode(0);pre.next = head;int cnt = 0;while (cnt < k - 1){if (temp.next == null){temp = head;}else {temp = temp.next;}cnt++;}while (temp != null){pre = pre.next;temp = temp.next;}ListNode cur = pre;while (pre.next != null){pre = pre.next;}while (head != cur){pre.next = new ListNode(head.val);pre = pre.next;head = head.next;}return cur;}
方法2:(0ms)
public static ListNode rotateRight(ListNode head, int k) {if(head == null || head.next == null || k <= 0) {return head;}int n = 0;ListNode p = head;while(p != null) {p = p.next;n++;}k = k%n;if(k == n || k == 0) {return head;}ListNode slow = head , fast = head;for(int i=0; i<n-1; i++) {if(i >= k) {slow = slow.next;}fast = fast.next;}ListNode ans = head;ans = slow.next; //slow为新链表头结点的前一个节点 slow.next = null; //在旧链表中将新链表头结点与之前的节点斩断fast.next = head; //旧链表的尾节点连接上旧链表的头结点return ans;}
66. 分隔链表 ② √
给你一个链表的头节点 head
和一个特定值 x
,请你对链表进行分隔,使得所有 小于 x
的节点都出现在 大于或等于 x
的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
示例 1:
输入:head = [1,4,3,2,5,2], x = 3 输出:[1,2,2,4,3,5]
示例 2:
输入:head = [2,1], x = 2 输出:[1,2]
提示:
- 链表中节点的数目在范围
[0, 200]
内 -100 <= Node.val <= 100
-200 <= x <= 200
方法1:(0ms)
public static ListNode partition(ListNode head, int x) {if (head == null || head.next == null){return head;}ListNode pre = new ListNode(0);pre.next = head;ListNode temp = head;ListNode newList = pre;while (temp != null && temp.val < x){temp = temp.next;pre = pre.next;}if (temp == null){return head;}ListNode cur = temp;ListNode newPre = new ListNode(0);newPre.next = temp;ListNode newCur = cur;while (cur != null){if (cur.val < x){newCur = cur.next;pre.next = new ListNode(cur.val);pre = pre.next;cur = newCur;newPre.next = cur;}else {cur = cur.next;newPre = newPre.next;}}pre.next = temp;return newList.next;}
方法2:(0ms):力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
public ListNode partition(ListNode head, int x) {ListNode smlDummy = new ListNode(0), bigDummy = new ListNode(0);ListNode sml = smlDummy, big = bigDummy;while (head != null) {if (head.val < x) {sml.next = head;sml = sml.next;} else {big.next = head;big = big.next;}head = head.next;}sml.next = bigDummy.next;big.next = null;return smlDummy.next;}作者:Krahets
链接:https://leetcode.cn/problems/partition-list/solutions/2362068/86-fen-ge-lian-biao-shuang-zhi-zhen-qing-hha7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。