23. 合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
第一种方法:维护size=K的小根堆
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
Queue pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
for (ListNode node: lists) {
if (node != null) {
pq.offer(node);
}
}
ListNode dummyHead = new ListNode(0);
ListNode tail = dummyHead;
while (!pq.isEmpty()) {
ListNode minNode = pq.poll();
tail.next = minNode;
tail = minNode;
if (minNode.next != null) {
pq.offer(minNode.next);
}
}
return dummyHead.next;
}
}
第二种方法:归并排序,把每个链表当做待排序的元素
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
return merge(lists, 0, lists.length - 1);
}
private ListNode merge(ListNode[] lists, int left, int right) {
if (left == right) return lists[left];
int mid = left + (right - left) / 2;
ListNode l1 = merge(lists, left, mid);
ListNode l2 = merge(lists, mid + 1, right);
return mergeTwoLists(l1, l2);
}
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
}
148. 排序链表
归并+快慢指针
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode fast = head.next, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode tmp = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(tmp);
ListNode h = new ListNode(0);
ListNode res = h;
while (left != null && right != null) {
if (left.val < right.val) {
h.next = left;
left = left.next;
} else {
h.next = right;
right = right.next;
}
h = h.next;
}
h.next = left != null ? left : right;
return res.next;
}
}
两个单链表是否相交
思路: 直接看两个链表的最后一个节点是否一致
static boolean isIntersect2(ListNode h1, ListNode h2){
ListNode p1 = h1, p2 = h2;
if(p1==null || h2==null) return false;
ListNode last1 = p1;
while(p1.next != null){
last1 = p1;
p1 = p1.next;
}
ListNode last2 = p2;
while (p2.next != null){
last1 = p2;
p2 = p2.next;
}
if(last1==last2){
return true;
}else return false;
}
两个单链表第一次相交的位置
思路:先让计算链表的长度,让最长的链表A先走 len(A)-len(B)步,然后两个链表一起走,第一个相交点,即为所求的点
static ListNode findFisrtCrossNode(ListNode h1, ListNode h2){
int lenA = len(h1);
int lenB = len(h2);
ListNode p1 = h1, p2 = h2;
ListNode tmp = null;
if(lenA > lenB) tmp = p1;
else tmp = p2;
for(int i=0; i lenB) p1=tmp;
else p2 = tmp;
while(p1!=null && p2!=null){
if(p1==p2) return p1;
p1 = p1.next;
p2 = p2.next;
}
return null;
}
static int len(ListNode h){
int clen = 0;
ListNode p = h;
while (p!=null){
p = p.next;
++clen;
}
return clen;
}
单链表是否有环
追逐法:
设置两个指针 fast, slow,将其初始化为链表的头结点;然后两个节点同时向前移动,fast一次移动2步,slow一次移动一步。如果存在环,fast指针和slow指针一定相遇。
static boolean hasCycle(ListNode h){
ListNode fast=h, slow=h;
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow && slow!=null){
return true;
}
}
return false;
}
链表翻转
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = NULL, *pre = head;
while (pre != NULL) {
ListNode* t = pre->next;
pre->next = cur;
cur = pre;
pre = t;
}
return cur;
}
};
# 两个链表生成相加链表
https://segmentfault.com/a/1190000040926678
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。给定两个这种链表,请生成代表两个整数相加值的结果链表。
示例:
输入:[9,3,7],[6,3]
返回值:{1,0,0,0}
分析问题:
由于两个数字相加是从个位数开始,然后再十位数、百位数。对于的链表中,我们需要将两个链表进行右端对齐,然后从右往左进行计算。
要想让两个链表右端对齐,我们有两种实现方式。
- 将两个链表进行反转,然后直接求和。
-
借助栈这种先进后出的特性,来实现链表的右端对齐。
我们先来看一下如何使用链表反转来实现。
class Solution(object):
def reverse(self, head):
cur = head
#初始化时,pre为None
pre = None
while cur:
next=cur.next
cur.next = pre
pre = cur
cur = next
return pre
def addTwoNumbers(self, l1, l2):
#将两个链表翻转
l1 = self.reverse(l1)
l2 = self.reverse(l2)
head=ListNode(0)
pre=head
#代表是否进位
carray=0
while l1 or l2:
v1=l1.val if l1 else 0
v2=l2.val if l2 else 0
sum=v1+v2+carray
#进位数
carray=int(sum/10)
tmp=sum%10
node=ListNode(tmp)
pre.next=node
pre=pre.next
if l1:
l1=l1.next
if l2:
l2=l2.next
if carray==1:
node=ListNode(carray)
pre.next=node
return self.reverse(head.next)
下面我们来看一下如何使用栈来求解。我们首先将两个链表从头到尾放入两个栈中,然后每次同时出栈,就可以实现链表的右端对齐相加,我们来看一下代码如何实现。
def addTwoNumbers(l1, l2):
#申请两个栈
stack1=[]
stack2=[]
#l1入栈
while l1:
stack1.append(l1.val)
l1 = l1.next
while l2:
stack2.append(l2.val)
l2 = l2.next
head = None
carry = 0
while stack1 and stack2:
num = stack1.pop() + stack2.pop() + carry
#求进位数
carry=int(num/10)
tmp=num%10
node = ListNode(tmp)
node.next = head
head = node
s = stack1 if stack1 else stack2
while s:
num = s.pop() + carry
carry = int(num / 10)
tmp = num % 10
node = ListNode(tmp)
node.next = head
head = node
if carry==1:
node = ListNode(carry)
node.next = head
head = node
return head