目录
栈
用两个栈实现队列
题目
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
数据范围: 𝑛≤1000n≤1000
要求:存储n个元素的空间复杂度为 𝑂(𝑛)O(n) ,插入与删除的时间复杂度都是 𝑂(1)O(1)
示例1
输入:["PSH1","PSH2","POP","POP"]
返回值:1,2
说明:"PSH1":代表将1插入队列尾部 "PSH2":代表将2插入队列尾部 "POP":代表删除一个元素,先进先出=>返回1 "POP":代表删除一个元素,先进先出=>返回2
示例2
输入:["PSH2","POP","PSH1","POP"]
返回值:2,1
分析
栈是先进后出,队列是先进先出,所以我们这里想到用两个栈来模拟队列。
一个用来输入数据,一个用来输出数据。
代码
java
java
import java.util.*;
import java.util.Stack;
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()){
return stack2.pop();
}
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
python
python
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2:
return self.stack2.pop()
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
包含min函数的栈
题目
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。
此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
数据范围:操作数量满足 0≤𝑛≤300 0≤n≤300 ,输入的元素满足 ∣𝑣𝑎𝑙∣≤10000 ∣val∣≤10000
进阶:栈的各个操作的时间复杂度是 𝑂(1) O(1) ,空间复杂度是 𝑂(𝑛) O(n)
示例:
输入: ["PSH-1","PSH2","MIN","TOP","POP","PSH1","TOP","MIN"]
输出: -1,2,1,-1
解析:
"PSH-1"表示将-1压入栈中,栈中元素为-1
"PSH2"表示将2压入栈中,栈中元素为2,-1
"MIN"表示获取此时栈中最小元素==>返回-1
"TOP"表示获取栈顶元素==>返回2
"POP"表示弹出栈顶元素,弹出2,栈中元素为-1
"PSH1"表示将1压入栈中,栈中元素为1,-1
"TOP"表示获取栈顶元素==>返回1
"MIN"表示获取此时栈中最小元素==>返回-1
示例1
输入: ["PSH-1","PSH2","MIN","TOP","POP","PSH1","TOP","MIN"]
返回值:-1,2,1,-1
分析
这个难的地方在于找到最小值。那么可以使用两个栈。在放入第一个元素的时候都放进去,然后继续在第一个栈中放入元素,如果当前元素小于第二个的栈顶元素,那么就压入
进栈的时候必须是stack2.peek()>=node,如果没有等于的话,对于:2 2,第二个2不会再压入,而弹出最小值以后栈变成空了,实际上弹出一次以后他的最小值还是2
代码
java
java
import java.util.*;
import java.util.Stack;
public class Solution {
Stack<Integer> stack1=new Stack<>();
Stack<Integer> stack2=new Stack<>();
public void push(int node) {
stack1.push(node);
if(stack2.isEmpty() ||stack2.peek()>=node){
stack2.push(node);
}
}
public void pop() {
if(stack1.isEmpty()){
return ;
}
int a=stack1.pop();
if(stack2.peek()==a){
stack2.pop();
}
}
public int top() {
return stack1.peek();
}
public int min() {
return stack2.peek();
}
}
python
python
# -*- coding:utf-8 -*-
class Solution:
stack1=[]
stack2=[]
def push(self, node):
# write code here
self.stack1.append(node)
if not self.stack2 or self.stack2[-1]>=node:
self.stack2.append(node)
def pop(self):
# write code here
if not self.stack1:
return
a=self.stack1.pop()
if self.stack2[-1]==a:
self.stack2.pop()
def top(self):
# write code here
return self.stack1[-1]
return
def min(self):
# write code here
return self.stack2[-1]
有效括号序列
题目
给出一个仅包含字符仅由括号字符 '[''['、']'']'、'(''('、')'')'、'{''{'、'}''}' 的括号序列字符串 𝑠s(0≦∣𝑠∣≦1040≦∣s∣≦104),你需要判断给出的括号序列字符串 𝑠s 是否是有效的括号序列。
有效括号序列的定义如下:
∙ ∙空序列是有效括号序列;
∙ ∙如果 𝐴A 是有效括号序列,则 (A)、[A] 和 A都是有效括号序列;
∙ ∙如果 𝐴A 和 𝐵B 都是有效括号序列,则它们的拼接 𝐴𝐵AB 也是有效括号序列。
如果括号序列字符串 𝑠 是有效的括号序列,返回一个布尔值 true;否则返回一个布尔值 false。
示例1
输入:"["
返回值:false
示例2
输入:"[]"
返回值:true
备注:要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)。
分析
用栈来实现,如果是左括号,那么压右括号入栈中,如果左括号不等于右括号,那么return fasle,如果循环结束栈中元素不为0,也return false
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return bool布尔型
*/
public boolean isValid (String s) {
// write code here
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(')');
}else if(s.charAt(i)=='['){
stack.push(']');
}else if(s.charAt(i)=='{'){
stack.push('}');
}else if(stack.isEmpty() || stack.peek()!=s.charAt(i)){
return false;
}else{
stack.pop();
}
}
return stack.isEmpty();
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param s string字符串
# @return bool布尔型
#
class Solution:
def isValid(self , s: str) -> bool:
# write code here
stack=[]
for i in range(len(s)):
if s[i]=='(':
stack.append(')')
elif s[i]=='[':
stack.append(']')
elif s[i]=='{':
stack.append('}')
elif not stack or stack[-1]!=s[i]:
return False
else:
stack.pop()
return False if stack else True
表达式求值
题目
请写一个整数计算器,支持加减乘三种运算和括号。
数据范围:0≤∣𝑠∣≤100,保证计算结果始终在整型范围内
要求:空间复杂度: 𝑂(𝑛),时间复杂度 𝑂(𝑛)
示例1
输入:"1+2"
返回值:3
示例2
输入:"(2*(3-4))*5"
返回值:-10
复制
示例3
输入:"3+2*3*4-1"
返回值:26
分析
定义两栈,一个存数字,一个存符号
代码
java
java
import java.util.*;
public class Solution {
public int solve (String s) {
int n = s.length();
return dfs(s.toCharArray(), 0, n - 1);
}
public int dfs(char[] s, int L, int R) {
Deque<Integer> nums = new ArrayDeque<>();
Deque<Integer> ops = new ArrayDeque<>();
int[] prior = new int[128];
prior['+'] = prior['-'] = 1;
prior['*'] = prior['/'] = 2;
nums.push(0); // 处理负数开头
for (int i = L; i <= R; i++) {
int c = s[i];
if (c >= '0' && c <= '9') { // 数字
int x = c - '0';
while (i + 1 <= R && s[i+1] >= '0' && s[i+1] <= '9') {
x = x * 10 + s[++i] - '0';
}
nums.push(x);
}
else if (c == '+' || c == '-' || c == '*' || c == '/') { // 运算符
calc(nums, ops, prior, c);
}
else if (c == '(') { // 括号,递归
int j = i + 1, level = 1;
while (level > 0) {
if (s[j] == '(') level++;
else if (s[j] == ')') level--;
j++;
}
nums.push(dfs(s, i + 1, j - 2));
i = j - 1;
}
}
calc(nums, ops, prior, '+'); // 把剩下的全部算完
return nums.pop();
}
public void calc(Deque<Integer> nums, Deque<Integer> ops, int[] prior, int c) {
while (!ops.isEmpty() && nums.size() > 1 && prior[ops.peek()] >= prior[c]) {
int op = ops.pop();
int y = nums.pop();
int x = nums.pop();
if (op == '+') x += y;
else if (op == '-') x -= y;
else if (op == '*') x *= y;
else if (op == '/') x /= y;
nums.push(x);
}
ops.push(c);
}
}
python
python
class Solution:
def solve(self , s: str) -> int:
return self.dfs(s, 0, len(s) - 1)
def dfs(self, s, L, R):
nums = []
ops = []
prior = {'+':1, '-':1, '*':2, '/':2}
nums.append(0) # 处理负数开头
i = L
while i <= R:
if s[i].isdigit():
x = 0
while i <= R and s[i].isdigit():
x = x * 10 + int(s[i])
i += 1
nums.append(x)
continue
c = s[i]
if c in "+-*/":
self.calc(nums, ops, prior, c)
i += 1
elif c == '(':
j = i + 1
level = 1
while level > 0:
if s[j] == '(':
level += 1
elif s[j] == ')':
level -= 1
j += 1
val = self.dfs(s, i+1, j-2)
nums.append(val)
i = j - 1
else:
i += 1
self.calc(nums, ops, prior, '+')
return nums.pop()
def calc(self, nums, ops, prior, c):
while ops and prior[ops[-1]] >= prior[c]:
op = ops.pop()
y = nums.pop()
x = nums.pop()
if op == '+':
x += y
elif op == '-':
x -= y
elif op == '*':
x *= y
elif op == '/':
x = int(x / y)
nums.append(x)
ops.append(c)
队列
滑动窗口的最大值
题目
给定一个长度为 n 的数组 num 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。
例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
窗口大于数组长度或窗口长度为0的时候,返回空。
数据范围: 1≤𝑛≤10000,0≤𝑠𝑖𝑧𝑒≤10000,数组中每个元素的值满足 ∣𝑣𝑎𝑙∣≤10000
要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛)
示例1
输入:[2,3,4,2,6,2,5,1],3
返回值:[4,4,6,6,6,5]
示例2
输入:[9,10,9,-7,-3,8,2,-6],5
返回值:[10,10,9,8]
示例3
输入:[1,2,3,4],5
返回值:[]
分析
Deque是两端都能进和出的操作
peekFirst()看最左边第一个元素(队头) 只拿出来看一眼,不删除
② peekLast() **看最右边最后一个元素(队尾)**只看不删
- 删除(看完就删掉) remove /poll 系列
③ removeFirst() 删掉最左边第一个元素
④ removeLast() 删掉最右边最后一个元素
- add 系列
⑤ addLast(x)从队尾右边加元素
⑥ addFirst(x) 从队头左边加元素

代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型一维数组
* @param size int整型
* @return int整型ArrayList
*/
public ArrayList<Integer> maxInWindows (int[] num, int size) {
// write code here
ArrayList<Integer> res=new ArrayList<>();
// write code here
if(num.length==0 ||size==0){
return res;
}
Deque <Integer> que=new LinkedList<>();
for(int j=0,i=1-size;j<num.length;i++,j++){
if(i>0 && que.peekFirst()==num[i-1]){
que.removeFirst();
}
while(!que.isEmpty() && que.peekLast()<=num[j]){
que.removeLast();
}
que.addLast(num[j]);
if(i>=0){
res.add(que.peekFirst());
}
}
return res;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param num int整型一维数组
# @param size int整型
# @return int整型一维数组
#
import collections
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
result=[]
if len(num)==0 or size==0:
return result
# write code here
que=collections.deque()
for j in range(len(num)):
i=j-size+1
if i>0 and que[0]==num[i-1]:
que.popleft()
while que and que[-1]<=num[j]:
que.pop()
que.append(num[j])
if i>=0:
result.append(que[0])
return result
数据流中的中位数
题目
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
数据范围:数据流中数个数满足 1≤𝑛≤1000 ,大小满足 1≤𝑣𝑎𝑙≤1000
进阶: 空间复杂度 𝑂(𝑛) , 时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑛)
示例1
输入:[5,2,3,4,1,6,7,0,8]
返回值:"5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00 "
说明:数据流里面不断吐出的是5,2,3...,则得到的平均数分别为5,(5+2)/2,3...
示例2
输入:[1,1,1]
返回值:"1.00 1.00 1.00 "
分析
设置两个队列:
a是从小到大,b是从大到小,a是较大的后半部分,b是较小的前半部分
代码
java
java
import java.util.*;
public class Solution {
Queue<Integer> a=new PriorityQueue<>();//由小到大
Queue<Integer> b=new PriorityQueue<>((a,b) ->b-a);//由大到小
public void Insert(Integer num) {
if(a.size()!=b.size()){
a.add(num);
b.add(a.poll());
}else{
b.add(num);
a.add(b.poll());
}
}
public Double GetMedian() {
if(a.size()==b.size()){
return (a.peek()+b.peek())/2.0;
}else{
return a.peek()*1.0;
}
}
}
python
python
# -*- coding:utf-8 -*-
from heapq import *
class Solution:
def __init__(self):
self.A=[]
self.B=[]
def Insert(self, num):
# write code here
if len(self.A) != len(self.B):
heappush(self.A, num)
heappush(self.B, -heappop(self.A))
else:
heappush(self.B, -num)
heappush(self.A, -heappop(self.B))
def GetMedian(self):
# write code here
return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0
python只有较小堆没有较大堆,所以取负号,然后在最后结果的时候再取回来
堆
最小的k个数
题目
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0≤𝑘,𝑛≤10000,数组中每个数的大小0≤𝑣𝑎𝑙≤1000
要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑘)
示例1
输入:[4,5,1,6,2,7,3,8],4
返回值:[1,2,3,4]
说明:返回最小的4个数即可,返回[1,3,2,4]也可以
示例2
输入:[1],0
返回值:[]
示例3
输入:[0,1,2,1,2],3
返回值:[0,1,1]
分析
利用小顶堆,最小的在尖尖上
小顶堆 :从小到大 (a, b) -> a - b 大顶堆: 从大到小 (a, b) -> b - a
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param input int整型一维数组
* @param k int整型
* @return int整型ArrayList
*/
public ArrayList<Integer> GetLeastNumbers_Solution (int[] input, int k) {
// write code here
ArrayList<Integer> res=new ArrayList<>();
PriorityQueue<Integer> p=new PriorityQueue<>((a,b) ->a-b);
for(int i:input){
p.add(i);
}
for(int i=0;i<k;i++){
res.add(p.poll());
}
return res;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param input int整型一维数组
# @param k int整型
# @return int整型一维数组
#
import heapq
class Solution:
def GetLeastNumbers_Solution(self , input: List[int], k: int) -> List[int]:
# write code here
# 结果列表
res = []
# Python 小顶堆(默认就是小顶堆,和Java (a,b)->a-b 等价)
heapq.heapify(input) # 直接把数组转成堆,效率更高
# 取出前k个最小的数
for _ in range(k):
res.append(heapq.heappop(input))
return res
python默认的堆就是小顶堆
寻找第k大
题目
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑛),空间复杂度 𝑂(1)
数据范围:0≤𝑛≤1000, 1≤𝐾≤𝑛,数组中每个元素满足 0≤𝑣𝑎𝑙≤10000000
示例1
输入:[1,3,5,2,2],5,3
返回值:2
示例2
输入:[10,10,9,9,8,7,5,6,4,3,4,2],12,3
返回值:9
说明:去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9
分析
首先要了解什么是快速排序:
快速排序在每一轮挑选一个基准函数,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成了两个部分。
代码
java
java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
Random r=new Random();
public int findKth (int[] a, int n, int K) {
// write code here
int target = a.length - K;//找到第k大的下标
int start = 0, end = a.length - 1;
int pivot = privot(a, start, end);
while (pivot != target) {
if (pivot > target) {
end = pivot - 1;
} else {
start = pivot + 1;
}
pivot = privot(a, start, end);
}
return a[pivot];
}
public int privot(int [] a,int start,int end){
int pri=r.nextInt(start-end+1)+start;
swap(a,pri,end);
int index=start-1;
for(int i=start;i<=end;i++){
if(a[i]<a[end]){
swap(a,i,++index);
}
}
swap(a,++index,end);
return index;
}
public void swap(int[] a,int i,int j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
python
python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param a int整型一维数组
# @param n int整型
# @param K int整型
# @return int整型
#
import random
class Solution:
def findKth(self , a: List[int], n: int, K: int) -> int:
# write code here
target=len(a)-K
start = 0
end = len(a) - 1
# 核心:循环找,直到下标 == target
while True:
p = self.privot(a, start, end) # 基准下标
if p == target:
return a[p]
elif p > target:
end = p - 1 # 去左边找
else:
start = p + 1 # 去右边找
def privot(self,a:List[int],start:int,end:int)-> int:
r=random.randint(start,end)
a[r],a[end]=a[end],a[r]
index=start-1
for i in range(start,end+1):
if a[i]<a[end]:
index+=1
a[index],a[i]=a[i],a[index]
index+=1
a[index],a[end]=a[end],a[index]
return index