将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]示例 2:
输入:l1 = [], l2 = [] 输出:[]示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
ListNode p1 = list1, p2 = list2;
while(p1 != null && p2 != null) {
if (p1.val > p2.val) {
p.next = p2;
p2 = p2.next;
}else {
p.next = p1;
p1 = p1.next;
}
p = p.next;
}
if (p1 != null) {
p.next = p1;
}
if (p2 != null) {
p.next = p2;
}
return dummy.next;
}
}
给你一个链表的头节点 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]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
// 需要考虑是遍历过程中,如何断掉指针,不然会出现环 即遍历过程中,既不会指针丢失,又需要删除过去的指向
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode dummy1 = new ListNode(-1);
ListNode dummy2 = new ListNode(-1);
ListNode p1 = dummy1, p2 = dummy2;
ListNode p = head;
while (p != null) {
if (p.val >= x) {
p2.next = p;
p2 = p2.next;
}else {
p1.next = p;
p1 = p1.next;
}
// 重要 !!! 如何断掉指针不丢失
// 先保存,再断掉,然后再赋值回去
ListNode tmp = p.next;
p.next = null;
p = tmp;
}
p1.next = dummy2.next;
return dummy1.next;
}
}
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
例如,一个链表有 6
个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6
。这个链表的倒数第 3
个节点是值为 4
的节点。
给定一个链表: 1->2->3->4->5, 和 k = 2. 返回链表 4->5
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
// 理解for循环
// index 代表偏移量, 0即为原位置,1往前走1步,数据为第2个;假设有5个元素,从首位置偏移,走5步,第5步偏移就跳出数组或者指向null了,写for循环最好写成左闭右开的;另外走k步,实际是第k + 1个元素;而假设有n个元素,倒数第k个元素,实际为第 n - k + 1 元素;而获取index元素,如果从0开始,第index个为 < index ,跳出即为第index元素
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode p1 = head;
for (int i = 0; i < k; i++) {
p1 = p1.next;
}
ListNode p2 = head;
while(p1 != null) {
p2 = p2.next;
p1 = p1.next;
}
return p2;
}
}
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
// 获取到时第 n + 1个元素,直接跳跃即可
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode (-1);
dummy.next = head;
ListNode x = findKNode(dummy, n + 1);
x.next = x.next.next;
return dummy.next;
}
private ListNode findKNode(ListNode head, int k) {
ListNode p = head;
for (int i = 0; i < k; i++) {
p = p.next;
}
ListNode p1 = head;
while (p != null) {
p1 = p1.next;
p = p.next;
}
return p1;
}
}
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点
输入:head = [1,2,3,4,5,6] 输出:[4,5,6] 解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode p1 = head, p2 = head;
while (p2 != null && p2.next != null) {
p2 = p2.next.next;
p1 = p1.next;
}
return p1;
}
}
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode p1 = head, p2 = head;
while (p2 != null && p2.next != null) {
p1 = p1.next;
p2 = p2.next.next;
if (p1 == p2) {
return true;
}
}
return false;
}
}
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next
指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null
。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。注意,pos
仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
// 数学题,假设两个指针前行,一个以一步一步走,一个以两步两步走,最终相遇,假设慢指针走了k步,快指针一定走了2k步,相差为k步,假设相遇点距离环起点为m步,则环其他部分一定为k - m 步,而此时起点距离环起点刚好也是k - m 步;对于这种题,以一圈考虑,考虑多圈倍数,会更难解决;
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode p1 = head, p2 = head;
while (p2 != null && p2.next != null) {
p1 = p1.next;
p2 = p2.next.next;
if (p1 == p2) break;
}
if (p2 == null || p2.next == null) {
return null;
}
p2 = head;
while(p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
}
给定一个已排序的链表的头 head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
示例 1:
输入:head = [1,2,3,3,4,4,5] 输出:[1,2,5]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
Map<Integer, Integer> count = new HashMap<>();
ListNode p = head;
while (p != null) {
count.put(p.val, count.getOrDefault(p.val, 0) + 1);
p = p.next;
}
ListNode dummy = new ListNode(-1);
dummy.next = head;
p = dummy;
while (p != null) {
ListNode unqiue = p.next;
while (unqiue != null && count.get(unqiue.val) > 1) {
unqiue = unqiue.next;
}
p.next = unqiue;
p = p.next;
}
return dummy.next;
}
}