155. 最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack()
初始化堆栈对象。
void push(int val)
将元素val推入堆栈。
void pop()
删除堆栈顶部的元素。
int top()
获取堆栈顶部的元素。
int getMin()
获取堆栈中的最小元素。
使用辅助栈的解法,空间复杂度 O ( n ) O(n) O(n)
class MinStack {
Stack<Integer> vals;
Stack<Integer> minVals;
public MinStack() {
vals = new Stack();
minVals = new Stack();
}
public void push(int val) {
vals.push(val);
if(minVals.isEmpty()) minVals.push(val);
else minVals.push(Math.min(val, minVals.peek()));
}
public void pop() {
minVals.pop();
vals.pop();
}
public int top() {
return vals.peek();
}
public int getMin() {
return minVals.peek();
}
}
不使用辅助栈的方法,空间复杂度 O ( 1 ) O(1) O(1)
class MinStack {
Stack<Long> diffs;
long minVal;
public MinStack() {
diffs = new Stack();
}
public void push(int val) {
if(diffs.isEmpty()){
diffs.push(0L);
minVal = val;
}else{
diffs.push((long)val - minVal);
minVal = Math.min(minVal, val);
}
}
public void pop() {
Long temp = diffs.pop();
if(temp < 0) minVal -= temp;
}
public int top() {//top是不能出栈的
System.out.println(diffs.peek());
return (int)(minVal + Math.max(diffs.peek(), 0));
}
public int getMin() {
return (int)minVal;
}
}
148.排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
递归归并
class Solution {
public ListNode sortList(ListNode head) {
ListNode dummy = new ListNode(-1, head);
// 获取链表的长度
int len = 0;
ListNode curr = head;
while (curr!=null) {
len++;
curr = curr.next;
}
// 循环遍历
// 外层遍历step 内层处理每step个元素进行一次merge
for (int step=1; step<len; step*=2) {
ListNode tail = dummy;
curr = dummy.next;
while (curr!=null) {
ListNode left = curr;
ListNode right = cut(left, step);
curr = cut(right, step);
tail.next = merge(left, right);
while (tail.next!=null) {
tail = tail.next;
}
}
}
return dummy.next;
}
// 将链表从from开始切掉前step个元素,返回后一个元素
public ListNode cut(ListNode from, int step) {
step--;
while (from!=null && step>0) {
from = from.next;
step--;
}
if (from==null) {
return null;
} else {
ListNode next = from.next;
from.next = null;
return next;
}
}
// 将两个有序链表合并成一个,返回合并后的头节点
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode();
ListNode curr = dummy;
while (l1!=null && l2!=null) {
if (l1.val<l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
if (l1!=null) {
curr.next = l1;
}
if (l2!=null) {
curr.next = l2;
}
return dummy.next;
}
}
快速排序
class Solution {
public ListNode sortList(ListNode head) {
return quickSort(head);
}
public ListNode quickSort(ListNode head) {
if (head==null || head.next==null) {
return head;
}
ListNode h1 = new ListNode();
ListNode h2 = new ListNode();
ListNode h3 = new ListNode();
ListNode t1 = h1;
ListNode t2 = h2;
ListNode t3 = h3;
ListNode curr = head;
int pivot = getMid(head).val; // 用中间节点的原因是,如果每次用最左边的结点,对于纯递增和纯递减的case就退化为O(n)
while (curr!=null) {
ListNode next = curr.next;
if (curr.val < pivot) {
curr.next = null;
t1.next = curr;
t1 = t1.next;
} else if (curr.val == pivot) {
curr.next = null;
t2.next = curr;
t2 = t2.next;
} else {
curr.next = null;
t3.next = curr;
t3 = t3.next;
}
curr = next;
}
// < 的链表和 > 的链表分别快排
h1 = quickSort(h1.next);
h3 = quickSort(h3.next);
// h1链表不一定有元素 h2链表一定有元素 先把h2、h3连起来
h2 = h2.next;
t2.next = h3;
// 如果h1链表为空 直接返回h2即可
// 否则找到h1链表的结尾,连上h2的头
if (h1==null) {
return h2;
} else {
t1 = h1;
// 找到t1链表的结尾
while (t1.next!=null) {
t1 = t1.next;
}
t1.next = h2;
return h1;
}
}
public ListNode getMid(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast!=null && fast.next!=null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
105.从前序与中序遍历序列构造二叉树
class Solution {
private HashMap<Integer,Integer> hash = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
for(int i = 0;i < n;i++){
hash.put(inorder[i],i);
}
return MybuildTree(preorder, 0, n - 1, inorder, 0 , n-1);
}
public TreeNode MybuildTree(int[] preorder,int pl,int pr,int[] inorder,int il,int ir){
if(pl > pr){
return null;
}
int pre_root = pl;
int in_root = hash.get(preorder[pre_root]);
TreeNode root = new TreeNode(preorder[pre_root]);
int size_left = in_root - il;
root.left = MybuildTree(preorder, pl + 1, pl + size_left, inorder, il, ir - 1);
root.right = MybuildTree(preorder, pl + size_left + 1, pr, inorder, in_root + 1, ir);
return root;
}
}
106.从中序与后序遍历序列构造二叉树
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
int n = postorder.length;
for (int i = 0; i < n; i++) {
map.put(inorder[i], i);
}
return myBuildTree(inorder, 0, n - 1, postorder, 0, n - 1);
}
public TreeNode myBuildTree(int[] inorder, int inLeft, int inRight, int[] postorder, int postLeft, int postRight) {
if (postLeft > postRight) {
return null;
}
TreeNode node = new TreeNode(postorder[postRight]);
int inorderIndex = map.get(postorder[postRight]);
int leftSize = inorderIndex - inLeft;
node.left = myBuildTree(inorder, inLeft, inorderIndex - 1, postorder, postLeft, postLeft + leftSize - 1);
node.right = myBuildTree(inorder, inorderIndex + 1, inRight, postorder, postLeft + leftSize, postRight - 1);
return node;
}
}