目录
***合并K个升序链表
1 题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入: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
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10 ^ 4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4
2 解题(Java)
采用分治合并算法,参考树的后序遍历。
代码
/**
* 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 mergeKLists(ListNode[] lists) {
if (lists.length==0) {
return null;
}
return merge(lists, 0, lists.length-1);
}
public ListNode merge(ListNode[] lists, int left, int right) {
if (left == right) {
return lists[left];
}
int mid = (left + right) / 2;
ListNode l1 = merge(lists, left, mid);
ListNode l2 = merge(lists, mid+1, right);
return mergeTwoLists(l1, l2);
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummyHead = new ListNode();
ListNode cur = dummyHead;
while(l1 != null && l2 != null) {
if (l2.val < l1.val) {
cur.next = new ListNode(l2.val);
l2 = l2.next;
} else {
cur.next = new ListNode(l1.val);
l1 = l1.next;
}
cur = cur.next;
}
cur.next = l1 != null ? l1 : l2;
return dummyHead.next;
}
}
3 复杂性分析
- 时间复杂度O(Nlogk):数组长度为k,数组中结点总数为N,树的每一层合并时间复杂度为O(N),共logk层,因此时间复杂度为O(Nlogk);
- 空间复杂度O(N + logk):递归深度O(logk),分治归并过程需要借助最大为O(N)的链表空间;
***表达式求值
1 题目描述
请写一个整数计算器,支持加减乘三种运算和括号。
示例1
输入
“1 + 2”
返回值
3
示例2
输入
“( 2 * ( 3 - 4 ) ) * 5”
返回值
-10
示例3
输入
“3 + 2 * 3 * 4 - 1”
返回值
26
2 解题(Java)
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
public int solve (String s) {
s = s.trim();
Deque<Integer> stack = new LinkedList<>();
int number = 0;
char sign = '+';
char[] charArray = s.toCharArray();
for (int i=0; i<charArray.length; i++) {
char c = charArray[i];
if (c == ' ') {
continue;
}
else if (Character.isDigit(c)) {
number = number * 10 + c - '0';
}
else if (c == '(') {
int j = i + 1;
int counterPartition = 1;
while (counterPartition > 0) {
if (charArray[j] == '(') counterPartition++;
else if (charArray[j] == ')') counterPartition--;
j++;
}
number = solve(s.substring(i+1, j-1));
i = j - 1;
}
if (!Character.isDigit(c) || i == charArray.length - 1) {
if (sign == '+') {
stack.push(number);
} else if (sign == '-') {
stack.push(-1 * number);
} else if (sign == '*') {
stack.push(stack.pop() * number);
} else if (sign == '/') {
stack.push(stack.pop() / number);
}
number = 0;
sign = c;
}
}
int ans = 0;
while (!stack.isEmpty()) {
ans += stack.pop();
}
return ans;
}
}
3 复杂性分析
- 时间复杂度O(N):N为字符串长度,需线性遍历一遍字符串;
- 空间复杂度O(N):N为字符串长度,栈中存储的元素数量不超过N;
排序链表***
1 题目描述
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
- 你可以在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目在范围 [0, 5 * 10 ^ 4] 内
- -10 ^ 5 <= Node.val <= 10 ^ 5
2 解题(Java)
题目解析
- 最适合链表的排序算法是归并排序。如果采用自顶向下的递归实现,则空间复杂度为O(log n),如果要达到O(1)的空间复杂度,则需要使用自底向上的实现方式;
- 首先求得链表的长度length,然后将链表拆分成子链表进行合并;
- 用subLength表示每次需要排序的子链表的长度,初始subLength=1;
- 每次将链表拆分成若干个长度为subLength的子链表(最后一个子链表的长度可以小于subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength * 2的有序子链表(最后一个子链表的长度可以小于subLength * 2);
- 将subLength的值加倍,重复4,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕;
代码
/**
* 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 sortList(ListNode head) {
int length = 0;
ListNode node = head;
while (node != null) {
node = node.next;
length++;
}
ListNode dummyHead = new ListNode(0, head);
for (int subLength = 1; subLength < length; subLength *= 2) {
ListNode prev = dummyHead, curr = dummyHead.next;
while (curr != null) {
ListNode head1 = curr;
for (int i=1; i<subLength && curr.next != null; i++) {
curr = curr.next;
}
ListNode head2 = curr.next;
curr.next = null;
curr = head2;
for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
curr = curr.next;
}
ListNode next = null;
if (curr != null) {
next = curr.next;
curr.next = null;
}
ListNode merged = merge(head1, head2);
prev.next = merged;
while (prev.next != null) {
prev = prev.next;
}
curr = next;
}
}
return dummyHead.next;
}
public ListNode merge(ListNode head1, ListNode head2) {
ListNode dummyHead = new ListNode();
ListNode temp = dummyHead;
while (head1 != null && head2 != null) {
if (head1.val <= head2.val) {
temp.next = head1;
head1 = head1.next;
} else {
temp.next = head2;
head2 = head2.next;
}
temp = temp.next;
}
temp.next = head1 == null ? head2 : head1;
return dummyHead.next;
}
}
3 复杂性分析
- 时间复杂度O(nlogn):其中 n 是链表的长度;
- 空间复杂度O(1);