题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/
思路:把两条链表往一个新的虚拟头结点上合并。
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode root = new ListNode(-1);
ListNode p1 = list1, p2 = list2, r = root;
while (p1 != null && p2 != null) {
if (p1.val < p2.val) {
r.next = p1;
p1 = p1.next;
} else {
r.next = p2;
p2 = p2.next;
}
r = r.next;
}
if (p1 != null) {
r.next = p1;
}
if (p2 != null) {
r.next = p2;
}
return root.next;
}
}
题目链接:https://leetcode.cn/problems/partition-list/
思路: 把思路转换为把一条链表拆分为两条链表,分别接在两个虚拟头结点上,每次拼接后要把拼接的节点截断,让其指向null,
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode r1 = new ListNode();
ListNode r2 = new ListNode();
ListNode p = head, p1 = r1, p2 = r2;
while (p != null) {
if (p.val < x) {
p1.next = p;
p1 = p1.next;
}else {
p2.next = p;
p2 = p2.next;
}
ListNode t = p.next;
p.next = null;
p = t;
}
p1.next = r2.next;
return r1.next;
}
}
题目链接:https://leetcode.cn/problems/merge-k-sorted-lists/
思路:合并K个升序数组,难点在于如何排列,需要比较每一条链表当前元素的最小值,这里需要借助优先级队列,PriorityQueue,先将每一条链表的头结点入队,然后再出队,出队后拼接新链表上,然后再把该出对结点的下一个节点入队进行排序,如此即可完成k有序条链表合并。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode root = new ListNode();
ListNode p = root;
PriorityQueue<ListNode> queue = new PriorityQueue<>(
lists.length, ((a, b) -> a.val - b.val)
);
for (ListNode list : lists) {
if (list != null) {
queue.add(list);
}
}
while (!queue.isEmpty()) {
ListNode poll = queue.poll();
p.next = poll;
if (poll.next != null) {
queue.add(poll.next);
}
p = p.next;
}
return root.next;
}
}
题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
思路: 查找链表倒数第k个元素是很经典的快慢指针的问题,把倒数问题转变为正数问题,只需快指针先走k步,然后再让慢指针指向头结点,此后快慢指针同步往前走,直至快指针走到尾部慢指针指向的位置即为要查找节点的前一个节点。
本题我做复杂了,不需要虚拟头结点,只需要先整一个for循环让快指针先走k步,然后再整一个while让快慢一起走。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode root = new ListNode(-1, head);
ListNode slow = null, fast = root;
int k = 0;
while (fast != null) {
if (k == n) {
slow = root;
}else if (k > n){
slow = slow.next;
}
fast = fast.next;
k++;
}
slow.next = slow.next.next;
return root.next;
}
}
题目链接:https://leetcode.cn/problems/middle-of-the-linked-list/
思路:找中间节点也是典型的快慢指针,只需要快指针每次比慢指针多走一步,当循环停止时,慢指针指向的即为中间节点。
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
题目链接:https://leetcode.cn/problems/linked-list-cycle/
思路:判断是否成环也是典型的快慢指针问题,如果有环的话,快指针每次比慢指针多走一步,一定会再和慢指针相遇,只要相遇就有环。
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}
}
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
思路:本题有一个取巧的方法,就是把遍历到的节点都放到hashset里去,只要出现重复,第一个重复的即为环的入口。
public class Solution {
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
ListNode p = head;
while (p != null) {
if (set.contains(p)) return p;
else set.add(p);
p = p.next;
}
return null;
}
}
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/
思路:判断两条链表是否有相交节点也是一道经典题目了,只需要先遍历得到两条链表的长度,
然后让比较长的那一条往前走几步,就走多的那几步,然后再两条链表同步向前走
只要有相等便有相交。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0, lenB = 0;
ListNode pa = headA, pb = headB;
while (pa != null) {
lenA++;
pa = pa.next;
}
while (pb != null) {
lenB++;
pb = pb.next;
}
pa = headA;
pb = headB;
if (lenA > lenB) {
for (int i = lenB; i < lenA; i++) {
pa = pa.next;
}
}
if (lenA < lenB) {
for (int i = lenA; i < lenB; i++) {
pb = pb.next;
}
}
while (pa != null && pb != null) {
if (pa == pb) return pa;
pa = pa.next;
pb = pb.next;
}
return null;
}
}