理论
第一章 刷题
232. 用栈实现队列
准备两个栈push和pop:用户给我的数永远进push栈、用户要的数据永远从pop拿;
如果有数据进来,则压入push栈
如果拿数据,看pop栈有没有,如果有,直接pop;如果没有,看push栈有没有;没有报错;有则让push栈数据全部进入pop栈,再返回栈顶。
倒这个行为有两个限制:1.如果push的数据要向pop栈倒,则必须一次性倒完;如果pop栈有东西,push栈一定不能倒。
class MyQueue {
Stack<Integer> push;
Stack<Integer> pop;
/** Initialize your data structure here. */
public MyQueue() {
push = new Stack<Integer>();
pop = new Stack<Integer>();
}
/** Push element x to the back of queue. */
public void push(int x) {
push.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
this.dao();
if (pop.isEmpty()) {
throw new RuntimeException("no data");
}
return pop.pop();
}
/** Get the front element. */
public int peek() {
this.dao();
if (pop.isEmpty()) {
throw new RuntimeException("no data");
}
return pop.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
this.dao();
return pop.isEmpty();
}
private void dao() {
if (!pop.isEmpty()) {
return;
}
while (!push.isEmpty()) {
pop.push(push.pop());
}
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
225. 用队列实现栈
其实实现起来很傻:无非就是如何放数据和如何取数据!
准备两个队列a和b
有数据放入,则放入队列a;取数据时,将队列a中数据放入b,要留一个弹出;再取还是如此
数永远保存在data队列,只有出或者peek操作时,才到help队列,然后又立刻索引变换过来。
就是这么简单:
class MyStack {
private Queue<Integer> data;
private Queue<Integer> help;
/** Initialize your data structure here. */
public MyStack() {
data = new LinkedList<Integer>();
help = new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
data.offer(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
if (data.isEmpty()) {
throw new RuntimeException("no data");
}
while (data.size() != 1) {
help.offer(data.poll());
}
swap();
return help.poll();
}
/** Get the top element. */
public int top() {
if (data.isEmpty()) {
throw new RuntimeException("no data");
}
while (data.size() != 1) {
help.offer(data.poll());
}
swap();
int num = help.poll();
data.offer(num);
return num;
}
/** Returns whether the stack is empty. */
public boolean empty() {
return data.isEmpty();
}
private void swap() {
Queue<Integer> temp = data;
data = help;
help = temp;
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
20. 有效的括号
系统中处处都是栈的应用!
由于栈结构的特殊性,非常适合做对称匹配类的题目。
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (stack.isEmpty() || ch == '(' || ch == '{' || ch == '[') {
stack.push(ch);
} else {
char left = stack.peek();
if ((left == '(' && ch == ')') || (left == '[' && ch == ']') || (left == '{' && ch == '}')) {
stack.pop();
} else {
return false;
}
}
}
return stack.isEmpty();
}
}
1047. 删除字符串中的所有相邻重复项
匹配问题都是栈的强项!
如果想不到栈,就很难办了!
实话说,官网代码比我写的好的多,我的就不贴了!
class Solution {
public String removeDuplicates(String S) {
StringBuffer stack = new StringBuffer();
int top = -1;
for (int i = 0; i < S.length(); ++i) {
char ch = S.charAt(i);
if (top >= 0 && stack.charAt(top) == ch) {
stack.deleteCharAt(top);
--top;
} else {
stack.append(ch);
++top;
}
}
return stack.toString();
}
}
150. 逆波兰表达式求值
有没有想过计算机是如何处理表达式的?
其实看到题目九知道怎么解了。
这里大家思考一下,怎么将一个我们可以看懂的式子转化成逆波兰表达法才是难点!
class Solution {
public int evalRPN(String[] tokens) {
Stack<String> stack = new Stack<String>();
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals("+") || tokens[i].equals("-") || tokens[i].equals("*") || tokens[i].equals("/")) {
stack.push(calculate(Integer.valueOf(stack.pop()), Integer.valueOf(stack.pop()), tokens[i]) + "");
} else {
stack.push(tokens[i]);
}
}
return Integer.valueOf(stack.pop());
}
private int calculate(int num2, int num1, String flag) {
if (flag.equals("+")) {
return num1 + num2;
} else if (flag.equals("-")) {
return num1 - num2;
} else if (flag.equals("*")) {
return num1 * num2;
} else {
return num1 / num2;
}
}
}
239. 滑动窗口最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length < k) {
return null;
}
int[] res = new int[nums.length - k + 1];
int index = 0;
LinkedList<Integer> qmax = new LinkedList<Integer>();
for (int i = 0; i < nums.length; i++) {
while (!qmax.isEmpty() && nums[qmax.peekLast()] <= nums[i]) {
qmax.pollLast();
}
qmax.addLast(i);
if (qmax.peekFirst() == i - k) {
qmax.pollFirst();
}
if (i >= k - 1) {
res[index++] = nums[qmax.peekFirst()];
}
}
return res;
}
}
347. 前 K 个高频元素
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>();
for (int num : nums) {
occurrences.put(num, occurrences.getOrDefault(num, 0) + 1);
}
// int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] m, int[] n) {
return m[1] - n[1];
}
});
for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) {
int num = entry.getKey(), count = entry.getValue();
if (queue.size() == k) {
if (queue.peek()[1] < count) {
queue.poll();
queue.offer(new int[]{num, count});
}
} else {
queue.offer(new int[]{num, count});
}
}
int[] ret = new int[k];
for (int i = 0; i < k; i++) {
ret[i] = queue.poll()[0];
}
return ret;
}
}