牛客网【面试必刷TOP101】~ 04 堆/栈/队列
BM42 用两个栈实现队列(★)
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if (stack2.isEmpty()) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
BM43 包含min函数的栈(★)
public class Solution {
Stack<Integer> valStack = new Stack<>();
Stack<Integer> minStack = new Stack<>();
public void push(int node) {
valStack.push(node);
if (minStack.isEmpty() || node <= minStack.peek()) {
minStack.push(node);
}
}
public void pop() {
int val = valStack.pop();
if (minStack.peek() == val) {
minStack.pop();
}
}
public int top() {
return valStack.peek();
}
public int min() {
return minStack.peek();
}
}
BM44 有效括号序列(★)
方法一:栈
public class Solution {
public boolean isValid (String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '{' || c == '[') {
stack.push(c);
} else {
if (c == ')') {
if (stack.isEmpty() || stack.peek() != '(') return false;
} else if (c == '}') {
if (stack.isEmpty() || stack.peek() != '{') return false;
} else if (c == ']') {
if (stack.isEmpty() || stack.peek() != '[') return false;
}
stack.pop();
}
}
return stack.isEmpty();
}
}
方法二:栈
public class Solution {
public boolean isValid (String s) {
Stack<Character> stack = new Stack<>();
stack.push('a');
for (char c : s.toCharArray()) {
if (c == '(' || c == '{' || c == '[') {
stack.push(c);
} else {
if (c == ')') {
if (stack.peek() != '(') return false;
} else if (c == '}') {
if (stack.peek() != '{') return false;
} else if (c == ']') {
if (stack.peek() != '[') return false;
}
stack.pop();
}
}
return stack.peek() == 'a';
}
}
BM45 滑动窗口的最大值(★★★)
方法一:暴力法(100ms)
public class Solution {
public ArrayList<Integer> maxInWindows (int[] nums, int size) {
ArrayList<Integer> res = new ArrayList<>();
if (nums.length == 0 || size == 0) return res;
for (int i = 0; i <= nums.length - size; i++) {
int maxVal = nums[i];
for (int j = i + 1; j < i + size; j++) {
maxVal = Math.max(maxVal, nums[j]);
}
res.add(maxVal);
}
return res;
}
}
方法二:优先队列1(212ms)
public class Solution {
public ArrayList<Integer> maxInWindows (int[] nums, int size) {
ArrayList<Integer> res = new ArrayList<>();
if (nums.length == 0 || size == 0) return res;
PriorityQueue<Integer> queue = new PriorityQueue<Integer>((a, b) -> b - a);
for (int i = 0; i < nums.length; i++) {
queue.offer(nums[i]);
if (queue.size() > size) {
queue.remove(nums[i - size]);
}
if (queue.size() == size) {
res.add(queue.peek());
}
}
return res;
}
}
方法三:优先队列2(214ms)
public class Solution {
public ArrayList<Integer> maxInWindows (int[] nums, int size) {
ArrayList<Integer> res = new ArrayList<Integer>();
if (nums.length == 0 || size == 0 || nums.length < size) return res;
int n = nums.length;
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> {
return a[0] == b[0] ? b[1] - a[1] : b[0] - a[0];
});
for (int i = 0; i < size; i++) pq.offer(new int[]{nums[i], i});
res.add(pq.peek()[0]);
for (int i = size; i < n; i++) {
pq.offer(new int[]{nums[i], i});
while (pq.peek()[1] <= i - size) pq.poll();
res.add(pq.peek()[0]);
}
return res;
}
}
方法四:单调队列(100ms)
public class Solution {
public ArrayList<Integer> maxInWindows (int[] nums, int size) {
ArrayList<Integer> res = new ArrayList<>();
if (nums.length == 0 || size == 0 || nums.length < size) return res;
Deque<Integer> queue = new LinkedList<>();
for (int i = 0; i < size; i++) {
while (!queue.isEmpty() && nums[i] > queue.peekLast()) {
queue.pollLast();
}
queue.offerLast(nums[i]);
}
res.add(queue.peekFirst());
for (int i = size; i < nums.length; i++) {
if (nums[i - size] == queue.peekFirst()) {
queue.pollFirst();
}
while (!queue.isEmpty() && nums[i] > queue.peekLast()) {
queue.pollLast();
}
queue.offerLast(nums[i]);
res.add(queue.peekFirst());
}
return res;
}
}
BM46 最小的K个数(★★)
方法一:库函数排序(29ms)
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
Arrays.sort(input);
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < k; i++) res.add(input[i]);
return res;
}
}
方法二:选择排序(36ms)
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < input.length - 1; i++) {
int x = i;
for (int j = i + 1; j < input.length; j++) {
if (input[j] < input[x]) x = j;
}
int temp = input[i];
input[i] = input[x];
input[x] = temp;
}
for (int i = 0; i < k; i++) res.add(input[i]);
return res;
}
}
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
Queue<Integer> queue = new PriorityQueue<>();
for (int x : input) queue.offer(x);
ArrayList<Integer> res = new ArrayList<>();
while (k-- > 0) res.add(queue.poll());
return res;
}
}
方法四:大根堆(131ms)
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
if (input == null || k == 0) return new ArrayList<Integer>();
Queue<Integer> queue = new PriorityQueue<Integer>((a, b) -> b - a);
for (int x : input) {
if (queue.size() < k) {
queue.offer(x);
} else if (x < queue.peek()) {
queue.poll();
queue.offer(x);
}
}
ArrayList<Integer> res = new ArrayList<>();
while (!queue.isEmpty()) res.add(queue.poll());
return res;
}
}
方法五:快速排序(25ms)
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
if (input.length == 0 || k == 0) return new ArrayList<Integer>();
int t = quickSearch(input, 0, input.length - 1, k - 1);
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < k; i++) res.add(input[i]);
return res;
}
private int quickSearch(int[] nums, int le, int ri, int k) {
int j = partition(nums, le, ri);
if (j == k) return j;
return j > k ? quickSearch(nums, le, j - 1, k) : quickSearch(nums, j + 1, ri,
k);
}
private int partition(int[] nums, int le, int ri) {
int v = nums[le];
int i = le, j = ri + 1;
while (true) {
while (++i <= ri && nums[i] < v);
while (--j >= le && nums[j] > v);
if (i >= j) break;
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
nums[le] = nums[j];
nums[j] = v;
return j;
}
}
BM47 寻找第K大(★★)
快速排序思想(23ms)
注意第k大和第k小
public class Solution {
public int findKth (int[] a, int n, int K) {
quickSearch(a, 0, n - 1, K - 1);
return a[K - 1];
}
private void quickSearch(int[] a, int le, int ri, int k) {
int j = partition(a, le, ri);
if (j == k) return;
if (j > k) {
quickSearch(a, le, j - 1, k);
} else {
quickSearch(a, j + 1, ri, k);
}
}
private int partition(int[] a, int le, int ri) {
int v = a[le];
int i = le, j = ri + 1;
while (true) {
while (++i <= ri && a[i] > v);
while (--j >= le && a[j] < v);
if (i >= j) break;
int t = a[i];
a[i] = a[j];
a[j] = t;
}
a[le] = a[j];
a[j] = v;
return j;
}
}
BM48 数据流中的中位数(★★)
public class Solution {
Queue<Integer> qa = new PriorityQueue<Integer>((a, b) -> a - b);
Queue<Integer> qb = new PriorityQueue<Integer>((a, b) -> b - a);
public void Insert(Integer num) {
qa.offer(num);
while (!qb.isEmpty() && qb.peek() > qa.peek()) {
qa.offer(qb.poll());
}
int sz = (qa.size() + qb.size() + 1) / 2;
while (qb.size() < sz) {
qb.offer(qa.poll());
}
}
public Double GetMedian() {
if (qa.size() < qb.size()) {
return (double)qb.peek();
} else {
return (double)(qb.peek() + qa.peek()) / 2.0;
}
}
}
BM49 表达式求值(★★)
逆波兰表达式(Reverse Polish notation)
将表达式求值拆分为:逆波兰表达式构造+逆波兰表达式求值
逆波兰表达式构造
平常的表达式如A+B*(C+D)+E/F
为中缀表达式,对应的后缀表达式为ABCD+*+EF/+
参考博客:逆波兰表达式(后缀表达式)
class Solution {
private class Operator {
char sign;
int lever; // + - * / ( 对应的优先级 1 1 2 2 0
public Operator(char sign, int lever) {
this.sign = sign;
this.lever = lever;
}
}
public ArrayList<String> getRPN(String str) {
ArrayList<String> resultList = new ArrayList<>();
Stack<Operator> operatorStack = new Stack<>();
StringBuffer number = new StringBuffer();
for (char c : str.toCharArray()) {
if (!isOperator(c)) {
number.append(c);
continue;
}
if (number.length() > 0) {
resultList.add(number.toString());
number.setLength(0);
}
switch(c) {
case '+': stackHelper(resultList, operatorStack, '+', 1); break;
case '-': stackHelper(resultList, operatorStack, '-', 1); break;
case '*': stackHelper(resultList, operatorStack, '*', 2); break;
case '/': stackHelper(resultList, operatorStack, '/', 2); break;
case '(': operatorStack.push(new Operator('(', 0)); break;
default:
while (!operatorStack.isEmpty() && operatorStack.peek().lever != 0) {
resultList.add(operatorStack.pop().sign + "");
}
if (!operatorStack.isEmpty() && operatorStack.peek().lever == 0) {
operatorStack.pop();
}
break;
}
}
if (number.length() > 0) {
resultList.add(number.toString());
}
while (!operatorStack.isEmpty()) {
resultList.add(operatorStack.pop().sign + "");
}
return resultList;
}
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
private void stackHelper(ArrayList<String> list, Stack<Operator> st, char c, int lever) {
while (!st.isEmpty() && st.peek().lever >= lever) {
list.add(st.pop().sign + "");
}
st.push(new Operator(c, lever));
}
}
测试代码:
public class MySolution {
public static void main(String[] args) {
Solution so = new Solution();
String str = "A+B*(C+D)+E/F";
ArrayList<String> res = so.getRPN(str);
for (String s : res) {
System.out.print(s);
}
// ABCD+*+EF/+
}
}
逆波兰表达式求值
力扣链接:150. 逆波兰表达式求值
输入:tokens = ["2","1","+","3","*"] 输出:9
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<Integer>();
Set<String> set = new HashSet<String>();
set.add("+");
set.add("-");
set.add("*");
set.add("/");
for (String token : tokens) {
if (!set.contains(token)) {
stack.push(Integer.valueOf(token));
} else {
int op2 = stack.pop();
int op1 = stack.pop();
if (token.equals("+")) {
stack.push(op1 + op2);
} else if (token.equals("-")) {
stack.push(op1 - op2);
} else if (token.equals("*")) {
stack.push(op1 * op2);
} else {
stack.push(op1 / op2);
}
}
}
return stack.pop();
}
}
方法整合(Accept)
import java.util.*;
public class Solution {
public int solve (String s) {
ArrayList<String> tokens = getRPN(s);
int result = evalRPN(tokens);
return result;
}
private class Operator {
char sign;
int lever; // + - * / ( 对应的优先级 1 1 2 2 0
public Operator(char sign, int lever) {
this.sign = sign;
this.lever = lever;
}
}
public ArrayList<String> getRPN(String str) {
ArrayList<String> resultList = new ArrayList<>();
Stack<Operator> operatorStack = new Stack<>();
StringBuffer number = new StringBuffer();
for (char c : str.toCharArray()) {
if (!isOperator(c)) {
number.append(c);
continue;
}
if (number.length() > 0) {
resultList.add(number.toString());
number.setLength(0);
}
switch (c) {
case '+':
stackHelper(resultList, operatorStack, '+', 1);
break;
case '-':
stackHelper(resultList, operatorStack, '-', 1);
break;
case '*':
stackHelper(resultList, operatorStack, '*', 2);
break;
case '/':
stackHelper(resultList, operatorStack, '/', 2);
break;
case '(':
operatorStack.push(new Operator('(', 0));
break;
default:
while (!operatorStack.isEmpty() && operatorStack.peek().lever != 0) {
resultList.add(operatorStack.pop().sign + "");
}
if (!operatorStack.isEmpty() && operatorStack.peek().lever == 0) {
operatorStack.pop();
}
break;
}
}
if (number.length() > 0) {
resultList.add(number.toString());
}
while (!operatorStack.isEmpty()) {
resultList.add(operatorStack.pop().sign + "");
}
return resultList;
}
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
private void stackHelper(ArrayList<String> list, Stack<Operator> st, char c,
int lever) {
while (!st.isEmpty() && st.peek().lever >= lever) {
list.add(st.pop().sign + "");
}
st.push(new Operator(c, lever));
}
private int evalRPN(ArrayList<String> tokens) {
Stack<Integer> stack = new Stack<Integer>();
Set<String> set = new HashSet<String>();
set.add("+");
set.add("-");
set.add("*");
set.add("/");
for (String token : tokens) {
if (!set.contains(token)) {
stack.push(Integer.valueOf(token));
} else {
int op2 = stack.pop();
int op1 = stack.pop();
if (token.equals("+")) {
stack.push(op1 + op2);
} else if (token.equals("-")) {
stack.push(op1 - op2);
} else if (token.equals("*")) {
stack.push(op1 * op2);
} else {
stack.push(op1 / op2);
}
}
}
return stack.pop();
}
}