//输入栈
Deque<Integer> instack;
//输出栈
Deque<Integer> outstack;
public MyQueue() {
//使用linkedlist来实现
instack = new LinkedList<Integer>();
outstack = new LinkedList<Integer>();
}
public void push(int x) {
instack.push(x);
}
public int pop() {
if(outstack.isEmpty()){
//将输入栈元素全部放入输出栈,此时输出栈的栈顶即为队列的对头
while(!instack.isEmpty()){
outstack.push(instack.pop());
}
}
return outstack.pop();
}
public int peek() {
if(outstack.isEmpty()){
while(!instack.isEmpty()){
outstack.push(instack.pop());
}
}
return outstack.peek();
}
public boolean empty() {
if(instack.isEmpty() && outstack.isEmpty()){
return true;
}
return false;
}
}
在java里,栈和队列基于linkedlist实现,分别提供了针对于栈和队列操作的不同方法。
用栈来实现队列,关键点在往出取元素时。输入栈作为输入使用,输入栈的栈底对应队列头,想要输出栈底元素,必须将栈底元素挪动到栈顶,因此要将输入栈元素全部移动到输出栈中
//1.使用两个队列
class MyStack {
//创建两个队列
Queue<Integer> queue1;
Queue<Integer> queue2;
public MyStack() {
queue1 = new LinkedList<Integer>();
queue2 = new LinkedList<Integer>();
}
public void push(int x) {
queue2.offer(x);
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
//交换两队列,保证queue2是一个空队列,实现最后加入的元素在队列头部
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
public int pop() {
//返回元素并删除
return queue1.poll();
}
public int top() {
//返回元素不删除
return queue1.peek();
}
public boolean empty() {
//因为每次加入元素之后将queue2赋给queue1,所以判断queue1即可
return queue1.isEmpty();
}
}
用队列实现栈,关键点在出栈时。要保证队列头是最后一次加入的元素。因此每一次添加元素时,都要保证所加元素在一个队列的头部;
//使用一个队列
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<Integer>();
}
public void push(int x) {
queue.offer(x);
//每添加一个新元素,保证此元素在队列的头部
int n = queue.size();
for(int i = 0;i < n - 1;i ++){
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
//1.自己想的
public boolean isValid(String s) {
Map<Character, Character> map = new HashMap<>();
map.put(')', '(');
map.put('}', '{');
map.put(']', '[');
Deque<Character> deque = new LinkedList<>();
char[] arr = s.toCharArray();
int len = arr.length;
if (len % 2 != 0) {
return false;
}
for (int i = 0; i < len; i++) {
if (!deque.isEmpty() && map.get(arr[i]) == deque.peek()) {
deque.pop();
} else {
deque.push(arr[i]);
}
}
return deque.isEmpty();
}
//2.不利用map
public boolean isValid2(String s) {
Deque<Character> stack = new LinkedList<>();
for(int i = 0;i < s.length();i ++){
char c = s.charAt(i);
//如果当前字符为左括号,将对应的右括号压入栈中
if(c == '('){
stack.push(')');
}else if(c == '{'){
stack.push('}');
}else if(c == '['){
stack.push(']');
//如果当前字符为右括号,如果栈为空或是不匹配
}else if(stack.isEmpty() || stack.peek() != c){
return false;
}else{
//当前字符为右括号,并且刚好匹配
stack.pop();
}
}
return stack.isEmpty();
}
//1.自己想的
public String removeDuplicates(String s) {
//或者使用ArrayDeque stack = new ArrayDeque<>();
//针对于添加/删除两端,ArrayDeque似乎更高效
Deque<Character> stack = new LinkedList<>();
int len = s.length();
for(int i = 0;i < len;i ++){
char ch = s.charAt(i);
if(!stack.isEmpty() && stack.peek() == ch){
stack.pop();
}else{
stack.push(ch);
}
}
StringBuilder sb = new StringBuilder();
while(!stack.isEmpty()){
sb.append(stack.pop());
}
sb.reverse();
return sb.toString();
}
//2.使用StringBuilder实现栈
public String removeDuplicates2(String s) {
//使用StringBuilder实现栈,append()对应push(),charAt()对应peek(),deleteCharAt()对应pop()
StringBuilder ans = new StringBuilder();
int len = s.length();
//用于指向ans的最后一个元素,便于取出比较和删除
int index = -1;
for(int i = 0;i < len;i ++){
char ch = s.charAt(i);
if(index >= 0 && ch == ans.charAt(index)){
ans.deleteCharAt(index);
index --;
}else{
ans.append(ch);
index ++;
}
}
return ans.toString();
}
//3.双指针,以abba为例走一遍就明白了
public String removeDuplicates3(String s) {
char[] arr = s.toCharArray();
int fast = 0;
int slow = 0;
while(fast < arr.length){
arr[slow] = arr[fast];
if(slow > 0 && arr[slow] == arr[slow - 1]){
slow --;
}else{
slow ++;
}
fast ++;
}
return new String(arr,0,slow);
}
//1.栈
public int evalRPN1(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
int len = tokens.length;
for(int i = 0;i < len;i ++){
String s = tokens[i];
if(!("+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s))){
stack.push(Integer.parseInt(s));
}else{
int a = stack.pop();
int b = stack.pop();
if("+".equals(s)) stack.push(b + a);
if("-".equals(s)) stack.push(b - a);
if("*".equals(s)) stack.push(b * a);
if("/".equals(s)) stack.push(b / a);
}
}
return stack.pop();
}
//2.用数组模拟栈
public int evalRPN2(String[] tokens) {
int len = tokens.length;
int[] arr = new int[len];
int index = -1;
for(int i = 0;i < len;i ++){
String s = tokens[i];
if(!("+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s))){
index ++;
arr[index] = Integer.parseInt(s);
}else{
int a = arr[index--];
int b = arr[index--];
switch(s){
case "+":
arr[++index] = a + b;
break;
case "-":
arr[++index] = b - a;
break;
case "*":
arr[++index] = b * a;
break;
case "/":
arr[++index] = b / a;
break;
}
}
}
return arr[index];
}
//1.单调队列
/*
* 维护一个单调队列,队列里包含当前窗口中的元素,且从队列头是从大到小,
* 每当滑动窗口向右移动,向返回数组中添加当前队列中的最大值
* */
public int[] maxSlidingWindow1(int[] nums, int k) {
Deque<Integer> deque = new LinkedList<>();
int len = nums.length + 1 - k;
int[] ans = new int[len];
int index = 0;
for (int i = 0; i < nums.length; i++) {
//维护队列是单调队列
while (!deque.isEmpty() && nums[i] > deque.getLast()) {
deque.removeLast();
}
deque.add(nums[i]);
//如果第一次达到k个元素,将队列中的最大值加入返回数组,不涉及元素的移除
if (i == k - 1) {
ans[index++] = deque.peek();
}
//如果不是第一次达到k个元素,涉及元素的移除
if (i >= k) {
//如果当前队列头元素刚好等于要移除的元素,则将队列头出队
if (!deque.isEmpty() && nums[i - k] == deque.peek()) {
deque.poll();
}
ans[index++] = deque.peek();
}
}
return ans;
}
时间复杂度O(nlogk),空间复杂度O(n)
//1.小顶堆
public int[] topKFrequent(int[] nums, int k) {
//使用map统计数组中各个数字出现的次数
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
//建立一个小顶堆,用来记录数组中出现频次前k的数字信息
//小顶堆的排序需要按照map中value的大小,但是小顶堆中实际存放的是map中的key,
//所以需要重写compare方法,按照value的值进行比较
PriorityQueue<Integer> minHeap = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
//遍历map中的key
for (Integer key : map.keySet()) {
//如果堆中元素的个数小于k,则持续加入
if (minHeap.size() < k) {
minHeap.add(key);
} else {
//否则的话,判断将要加入元素对应的value值是否大于堆顶元素对应的value值
//如果是,则堆顶元素出,新元素入
if (map.get(key) > map.get(minHeap.peek())) {
minHeap.poll();
minHeap.add(key);
}
}
}
int[] ans = new int[k];
int index = 0;
//最终小顶堆中的k个数即为出现频次最高的前k个数
for (Integer i : minHeap) {
ans[index++] = i;
}
return ans;
}