目录
用栈实现队列(Leetcode232)
package 栈和队列;
import java.util.ArrayList;
import java.util.Stack;
思路:
1、用一个栈stack2来存压入的数,当要pop或peek操作时再压入stack中,实现队列顺序
2、不是每次pop都从stack2中压入数据,要stack中为空,也就是上一次压入的几个数pop完才可以再次压入新数据
public class 用栈实现队列 {
public static void main(String[] args) {
}
//创建2个栈 stack1用来反转顺序辅助
static Stack<Integer> stack;
static Stack<Integer> stack2;
//先存在辅助栈中,比如 1 2 3 4
public void push(int x) {
stack2.push(x);
}
public int pop() {
if(stack.isEmpty()){ //要先判断stack是否有未输出完的数字 这里为什么需要stack为空,因为比如现在stack里面的是4321,pop一次后变成432
//这时push一次5 然后在pop 发现是输出5和队列不符 可以自己把判断stack为空的条件去掉验证一下,要将stack里面的数pop完才可以从stack2压新数
if(!stack2.isEmpty()) {
while(!stack2.isEmpty()) { //将之前的输入存入 这时候就是4321了
stack.push(stack2.pop());
}
}
}
return stack.pop(); //pop的就是1了
}
//和pop一样的道理
public int peek() {
if(stack.isEmpty()){
if(!stack2.isEmpty()) {
while(!stack2.isEmpty()) {
stack.push(stack2.pop());
}
}
}
return stack.peek();
}
public boolean empty() {
if (stack.empty() && stack2.empty()) {
return true;
} else {
return false;
}
}
}
用队列实现栈(Leetcode225)
//直接使用双向队列即可
class MyStack {
static Deque<Integer> de;
public MyStack() {
this.de = new LinkedList<>();
}
public void push(int x) {
de.add(x);
}
public int pop() {
return de.pollLast();
}
public int top() {
return de.peekLast();
}
public boolean empty() {
return de.isEmpty();
}
}
有效的括号(Leetcode20)
//思路
//1、使用到了栈的思想
//2、左括号入栈,遍历到右括号则从栈中弹出,看看是否匹配上
//3、额外情况,左括号太多或者右括号太多
public static boolean isValid(String s) {
Deque<Character> de = new LinkedList<>();
for(int i = 0 ;i<s.length();i++) {
char temp = s.charAt(i);
if(temp=='('||temp=='{'||temp=='[') {
de.addLast(temp);
}else if(temp==')'||temp=='}'||temp==']') {
//右括号多出来了
if(de.isEmpty()) {
return false;
}
if(temp==')'&&de.peekLast()=='(') {
de.pollLast();
}else if(temp=='}'&&de.peekLast()=='{') {
de.pollLast();
}else if(temp==']'&&de.peekLast()=='[') {
de.pollLast();
}else {
return false;
}
}
}
//额外情况,左括号太多
if(!de.isEmpty()) {
return false;
}else {
return true;
}
}
删除字符串中的所有相邻重复项(Leetcode1047)
思路,直接用栈思想即可,相邻且不同同或者栈为空则入栈,如果相同则把相同的数弹出
static Deque<Character> de = new LinkedList<>();
public static String removeDuplicates(String s) {
char[] arr = s.toCharArray();
for(int i = 0;i<arr.length;i++) {
if(de.isEmpty()||de.peekLast()!=arr[i]) {
de.addLast(arr[i]);
}else {
de.pollLast();
}
}
StringBuilder str = new StringBuilder();
while(!de.isEmpty()) {
str.append(de.pollFirst());
}
return new String(str);
}
逆波兰表达式求值(Leetcode150)
思路:遇见数字就入栈,遇见运算符号就弹出2个进行运算后再入栈
注意:
1、因为输入的是字符串所以用Character.isDigit(tokens[i].charAt(0))来判断遍历到的是不是字符
2、由于可能存在“-123”这样的数,当纯用tokens[i].charAt(0)来判断可能会误判为减号,所以如果长度>1,直接入栈即可
3、运算时哪个在前哪个在后要注意,-和/是先出栈的在后
//遇见数字就入栈,预计运算字符就弹出两个进行运算 然后把运算后的再次入栈
static Deque<String> de = new LinkedList<>();
public static int evalRPN(String[] tokens) {
for(int i = 0;i<tokens.length;i++) {
if(tokens[i].length()>1||Character.isDigit(tokens[i].charAt(0))){
de.addLast(tokens[i]);
}else {
int a1 = Integer.parseInt(de.pollLast());
int a2 = Integer.parseInt(de.pollLast());
int temp=0;
if(tokens[i].charAt(0)=='+') {
temp = a1+a2;
}else if(tokens[i].charAt(0)=='*') {
temp= a1*a2;
}else if(tokens[i].charAt(0)=='/') {
temp = a2/a1; //注意
}else if(tokens[i].charAt(0)=='-') {
temp = a2-a1; //注意
}
de.addLast(String.valueOf(temp));
}
}
return Integer.parseInt(de.peekLast());
}
滑动窗口最大值(Leetcode239)
思路:单调队列
1、如果遍历的数与队首的值相同时,队首出队
2、如果遍历到的数比队尾小,入队
3、如果遍历到的数比队尾大,则队尾出队直到队尾的数大于这个数为止,再把这个数入队
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length - k + 1;
//存放结果元素的数组
int[] res = new int[len];
int idx=0;
Myque que = new Myque();
for(int i = 0;i<k;i++) {
que.push(nums[i]);
}
res[idx++]=que.peek_first(); //先存第一个区间的
for(int i = k;i<nums.length;i++) { //主要就是看区间第一个和最后一个数是否满足条件
que.pop(nums[i-k]); //区间头
que.push(nums[i]); //区间尾
res[idx++] = que.peek_first();
}
return res;
}
class Myque{
private Deque<Integer> de;
public Myque() {
de = new LinkedList<>();
}
public void push(int value) {
while(!de.isEmpty()&&de.peekLast()<value) { //判断队尾是否需要出队
de.pollLast();
}
de.addLast(value);
}
public void pop(int value) {
if(!de.isEmpty()&&de.peekFirst()==value) { //判断是否需要队首出队
de.pollFirst();
}
}
public int peek_first() {
return de.peekFirst();
}
}
前K个高频的数(Leetcode347)
//思路 用小顶堆思想
//1、先用map计算每个元素的出现频率
//2、重写java中使用PriorityQueue类实现堆,构造函数一般可传入两个参数(size,new Comparator())
//①size:初始化堆的大小,若不传则默认为11,并且堆的大小会根据实际情况,自动扩展
//②new Comparator():定义了堆排序的比较方式。默认排序为小顶堆,若要实现大顶堆,则需要重写Comparator类的compare方法(见大顶堆);
//默认按自然排序,若要自定义排序方法,
//3、遍历Key入队
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0;i<nums.length;i++) {
map.put(nums[i],(map.getOrDefault(nums[i], 0)+1));
}
PriorityQueue<Integer> pr = new PriorityQueue<>(k,new Comparator<Integer>() {
@Override
public int compare(Integer a,Integer b) {
return map.get(a)-map.get(b);
}
});
int size = 0;
for(int j:map.keySet()) {
if(size<k) { //前k个入队
pr.offer(j);
size++;
}else if(map.get(pr.peek())<map.get(j)) { //比队首大,则队首出队 这个数入队
pr.poll();
pr.add(j);
}
}
int[] res = new int[k];
int idx = 0;
while(!pr.isEmpty()) {
res[idx++] = pr.poll();
}
return res;
}