如果有错的还请各位大佬指出呀
有些是copy的还望不要介意
本人只做学习记录
问题描述:
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
class MinStack {
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new LinkedList<>();
minStack = new LinkedList<>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int val) {
stack.push(val);
//也就是每次主栈存入一个数辅助栈都会存当前最小的数,保证两个栈长度相同
minStack.push(Math.min(val,minStack.peek()));
}
public void pop() {
//出栈时两个都出
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
辅助栈
时间O(1),空间O(n)
class MinStack {
Stack<Integer> stack;
Stack<Integer> minStack;
public MinStack() {
stack = new Stack<Integer>();
minStack = new Stack<Integer>();
}
public void push(int val) {
stack.push(val);
if(minStack.isEmpty() || minStack.peek() >= val){
minStack.push(val);
}
}
public void pop() {
if(stack.pop().equals(minStack.peek())){
minStack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
class MinStack {
Stack<Integer> stack;
int min = Integer.MAX_VALUE;
public MinStack() {
stack = new Stack<>();
}
public void push(int val) {
if(val <= min){
//将之前的min先入栈,也就是说之前的最小值和此时的最小值是在一起的
stack.push(min);
//再更新最小值
min = val;
}
stack.push(val);
}
public void pop() {
//如果出栈的值为最小值,先出栈该值
if(stack.pop() == min){
//并把下一个值也出栈,此时该值为最小值
//也就是说出栈为最小值时记得把记录前一个最小值也出栈
min = stack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
public class MinStack {
//long类型是因为保存的是差值可能会溢出
long min;
Stack<Long> stack;
public MinStack(){
stack=new Stack<>();
}
public void push(int val) {
if (stack.isEmpty()) {
min = val;
stack.push(val - min);
} else {
//如果该值小于最小值则保存的是负数
stack.push(val - min);
if (val < min){
min = val;
}
}
}
public void pop() {
if (stack.isEmpty())
return;
long pop = stack.pop();
//此时值是负数,说明之前这里更新了 min,之前的min=上一个min-此时的负值
if (pop < 0) {
min = min - pop;
}
}
public int top() {
long top = stack.peek();
//负数的话,值保存在 min 中
if (top < 0) {
return (int) (min);
} else {
//栈顶值加上最小值即可
return (int) (top + min);
}
}
public int getMin() {
return (int) min;
}
}
题目描述:
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题
示例:
输入: [3,2,1,5,6,4], k = 2
输出: 5
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length-k];
}
}
快排
时间O(n)空间O(1)
class Solution {
private final static Random random = new Random();
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
int target = len - k;
int left = 0;
int right = len - 1;
while(true){
int pivotIndex = partition(nums,left,right);
if(pivotIndex == target){
//当此时的下标等于target便是找到此位置
return nums[target];
}else if(pivotIndex < target){
left = pivotIndex + 1;
}else if(pivotIndex > target){
right = pivotIndex - 1;
}
}
}
private int partition(int[] nums,int left,int right){
//选取随机数来测试防止极端情况
int randomIndex = left + random.nextInt(right - left + 1);
//应对极端情况,防止递归树加深,循环开始前调换第一个与后面随机的一个数的位置
swap(nums,left,randomIndex);
int pivot = nums[left];
int le = left + 1;
int ge = right;
while(left >= right){
while(le <= ge && nums[le] < pivot){
le++;
}
while(le <= ge && nums[ge] > pivot){
ge--;
}
if(le>ge){
break;
}
swap(nums,le,ge);
le++;
ge--;
}
swap(nums,left,ge);
return ge;
}
private void swap(int[] nums,int left,int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
//优先队列默认是小根堆
Queue<Integer> max = new PriorityQueue<>(k);
for(int i=0;i<k;i++){
max.add(nums[i]);
}
int len = nums.length;
for(int i=k;i<len;i++){
Integer top = max.peek();
if(top<nums[i]){
max.poll();
max.add(nums[i]);
}
}
return max.peek();
}
}
题目描述:
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:
如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
class MedianFinder {
Queue<Integer> min,max;
public MedianFinder() {
//小根堆,存储较大的数
min = new PriorityQueue<>();
//大根堆,存储较小的数
max = new PriorityQueue<>((x,y) -> (y-x));
}
public void addNum(int num) {
//规定大根堆比小根堆的数量多1个
if(min.size() == max.size()){
//偶数时,先把数存入小根堆,再把小根堆中最小的元素存入大根堆
min.add(num);
max.add(min.poll());
}else{
//基数时,先存入大根堆,再把最大的元素存入小根堆
max.add(num);
min.add(max.poll());
}
}
public double findMedian() {
if(min.size() == max.size()){
return (min.peek()+max.peek())/2.0;
}else{
return max.peek()*1.0;
}
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
题目描述:
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2) 的解决方案
示例:
输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
输出:13
解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13
进阶:
你能否用一个恒定的内存(即 O(1) 内存复杂度)来解决这个问题?
你能在 O(n) 的时间复杂度下解决这个问题吗?这个方法对于面试来说可能太超前了,但是你会发现阅读这篇文章( this paper )很有趣。
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length;
int n = matrix[0].length;
int[] ans = new int[m*n];
int index = 0;
for(int[] temp : matrix){
for(int num:temp){
ans[index++] = num;
}
}
Arrays.sort(ans);
return ans[k-1];
}
}
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int m = matrix.length;
int n = matrix[0].length;
int min = matrix[0][0];
int max = matrix[m-1][n-1];
while(min<max){
int mid = left + (right - left) / 2;
//查找小于mid的数有多少个
int count = find(matrix,mid,m,n);
if(count<k){
//数量小于k代表第k小的元素在右边
min = mid + 1;
}else{
//数量大于等于k代表第k小的元素在左边
max = mid;
}
}
return max;
}
private int find(int[][] matrix,int mid,int m,int n){
int i=m - 1;
int j=0;
int count = 0;
while(i>=0 && j<n){
if(matrix[i][j]<=mid){
//该数比mid小,则该数所在列的前面几列都小
count += i+1;
j++;
}else{
i--;
}
}
return count;
}
}
class Solution {
public int kthSmallest(int[][] matrix, int k) {
Queue<Integer> queue = new PriorityQueue<>((x,y) -> (y-x));
for(int i=0;i<matrix.length;i++){
for(int j=0;j<matrix[0].length;j++){
queue.add(matrix[i][j]);
if(queue.size() > k){
queue.poll();
}
}
}
return queue.peek();
}
}
题目描述:
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
提示:
1 <= nums.length <= 105
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n)
,其中 n
是数组大小。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
//统计出现次数
Map<Integer,Integer> map = new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>(){
public int compare(int[] m,int[] n){
//根据count来排序
return m[1] - n[1];
}
});
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
int num = entry.getKey() , count = entry.getValue();
if(queue.size() == k){
//若堆顶小于新的值则替换
if(queue.peek()[1] < count){
queue.poll();
queue.add(new int[]{num,count});
}
}else{
queue.add(new int[]{num,count});
}
}
int[] ans = new int[k];
for(int i=0;i<k;i++){
ans[i] = queue.poll()[0];
}
return ans;
}
}
class Solution {
private final static Random random = new Random();
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
List<int[]> list = new ArrayList<>();
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
int num = entry.getKey(),count = entry.getValue();
list.add(new int[]{num,count});
}
int[] ans = new int[k];
qsort(list,0,list.size()-1,ans,0,k);
return ans;
}
private void qsort(List<int[]> list,int left,int right,int[] ans,int ansIndex,int k){
//取随机数防止极端情况
int randomIndex = left + random.nextInt(right-left+1);
//应对极端情况,防止递归树加深,开始前调换第一个与后面随机的一个数的位置
Collections.swap(list,left,randomIndex);
int pivot = list.get(left)[1];
int index = left;
for(int i = left+1;i<=right;i++){
if(list.get(i)[1] > pivot){
Collections.swap(list,index+1,i);
index++;
}
}
Collections.swap(list,index,left);
if(index-left >= k){
qsort(list,left,index-1,ans,ansIndex,k);
}else{
for(int i=left;i<=index;i++){
ans[ansIndex++] = list.get(i)[0];
}
if(k > index - left +1){
qsort(list,index+1,right,ans,ansIndex,k- (index-left+1));
}
}
}
}
题目描述:
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums == null || nums.length <= 1){
return nums;
}
//用队列存放滑动窗口内可能为最大值的下标
LinkedList<Integer> queue = new LinkedList<>();
int[] ans = new int[nums.length-k+1];
int index = 0;
for(int i=0;i<nums.length;i++){
//队尾元素小于此时的数则删除
while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]){
queue.pollLast();
}
queue.add(i);
//判断此时队首元素是否还在滑动窗口内
//若队尾下标-k=队首下标,则表示队首在滑动窗口外
if(queue.peekLast() - k == queue.peek()){
queue.poll();
}
//队首元素永远是最大的
if(i+1 >= k){
ans[index++] = nums[queue.peek()];
}
}
return ans;
}
}
分块+预处理
类似于稀疏表,稀疏表解决的是区间最值问题
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int[] prefixMax = new int[n];
int[] suffixMax = new int[n];
for (int i = 0; i < n; ++i) {
if (i % k == 0) {
prefixMax[i] = nums[i];
}
else {
prefixMax[i] = Math.max(prefixMax[i - 1], nums[i]);
}
}
for (int i = n - 1; i >= 0; --i) {
if (i == n - 1 || (i + 1) % k == 0) {
suffixMax[i] = nums[i];
} else {
suffixMax[i] = Math.max(suffixMax[i + 1], nums[i]);
}
}
int[] ans = new int[n - k + 1];
for (int i = 0; i <= n - k; ++i) {
ans[i] = Math.max(suffixMax[i], prefixMax[i + k - 1]);
}
return ans;
}
}
题目描述:
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例:
输入:s = "3+2*2"
输出:7
输入:s = " 3/2 "
输出:1
提示:
1 <= s.length <= 3 * 105
s 由整数和算符 (‘+’, ‘-’, ‘*’, ‘/’) 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
题目数据保证答案是一个 32-bit 整数
class Solution {
public int calculate(String s) {
Deque<Integer> stack = new ArrayDeque<>();
//将符号先设为+,方便第一个数存储
char symbol = '+';
int num = 0;
int n = s.length();
for(int i=0;i<n;i++){
//如果该元素是数字
if(Character.isDigit(s.charAt(i))){
//数字可能不止只有一位
num = num * 10 + s.charAt(i) - '0';
}
//i==n-1,当他是最后一个元素时,进行这个数与它前面的运算符的运算
if(!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n-1){
switch(symbol){
case '+':
stack.push(num);
break;
case '-':
stack.push(-num);
break;
case '*':
//将结果存入
stack.push(stack.pop() * num);
break;
default:
stack.push(stack.pop() / num);
}
num = 0;
symbol = s.charAt(i);
}
}
int ans = 0;
while(!stack.isEmpty()){
ans += stack.pop();
}
return ans;
}
}
class Solution {
//使用一个Map来维护运算符优先级
Map<Character,Integer> map = new HashMap<>(){{
put('+',1);
put('-',1);
put('*',2);
put('/',2);
put('%',2);
put('^',3);
}};
public int calculate(String s) {
//去除所有空格
s = s.replaceAll(" ","");
char[] cs = s.toCharArray();
int n = s.length();
//存放数字
Deque<Integer> nums = new ArrayDeque();
//为了防止第一个数是负数,将第一个数设置为0
nums.addLast(0);
//存放符号(也就是非数字操作)
Deque<Character> ops = new ArrayDeque<>();
for(int i=0;i<n;i++){
char c = cs[i];
if(c == '('){
ops.addLast(c);
}else if(c == ')'){
//计算到最近的(左括号
while(!ops.isEmpty()){
if(ops.peekLast() != '('){
calc(nums,ops);
}else{
ops.pollLast();
break;
}
}
}else{
if(Character.isDigit(c)){
int num = 0;
int j=i;
//防止有些数不只有一位
while(j<n && Character.isDigit(cs[j])){
num = num * 10 + (cs[j++] - '0');
}
nums.addLast(num);
i = j-1;
}else{
if(i>0 && (cs[i-1] == '(' || cs[i-1] == '+' || cs[i-1] == '-')){
nums.addLast(0);
}
//有新符号前先比较与前一个的优先级,先把前面能先计算的算
while(!ops.isEmpty() && ops.peekLast() != '('){
char pre = ops.peekLast();
if(map.get(pre) >= map.get(c)){
calc(nums,ops);
}else{
break;
}
}
ops.addLast(c);
}
}
}
//将剩余的算完
while(!ops.isEmpty()){
calc(nums,ops);
}
return nums.peekLast();
}
private void calc(Deque<Integer> nums,Deque<Character> ops){
if(nums.isEmpty() || nums.size()<2)return;
if(ops.isEmpty()) return;
int b = nums.pollLast(),a = nums.pollLast();
char op = ops.pollLast();
int ans = 0;
if(op == '+') ans = a+b;
else if(op == '-') ans = a-b;
else if(op == '*') ans = a*b;
else if(op == '/') ans = a/b;
else if(op == '%') ans = a%b;
else if(op == '^') ans = (int)Math.pow(a,b);
nums.addLast(ans);
}
}
题目描述:
给你一个嵌套的整数列表 nestedList 。每个元素要么是一个整数,要么是一个列表;该列表的元素也可能是整数或者是其他列表。请你实现一个迭代器将其扁平化,使之能够遍历这个列表中的所有整数。
实现扁平迭代器类 NestedIterator :
NestedIterator(List nestedList) 用嵌套列表 nestedList 初始化迭代器。
int next() 返回嵌套列表的下一个整数。
boolean hasNext() 如果仍然存在待迭代的整数,返回 true ;否则,返回 false 。
你的代码将会用下述伪代码检测:
initialize iterator with nestedList
res = []
while iterator.hasNext()
append iterator.next() to the end of res
return res
如果 res
与预期的扁平化列表匹配,那么你的代码将会被判为正确。
示例:
输入:nestedList = [[1,1],2,[1,1]]
输出:[1,1,2,1,1]
解释:通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,1,2,1,1]。
深度优先搜索+ 数组
时间O(n)空间O(n)
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List getList();
* }
*/
public class NestedIterator implements Iterator<Integer> {
private List<Integer> vals;
private Iterator<Integer> cur;
public NestedIterator(List<NestedInteger> nestedList) {
vals = new ArrayList<>();
dfs(nestedList);
cur = vals.iterator();
}
@Override
public Integer next() {
return cur.next();
}
@Override
public boolean hasNext() {
return cur.hasNext();
}
private void dfs(List<NestedInteger> nestedList){
for(NestedInteger ni:nestedList){
if(ni.isInteger()){
vals.add(ni.getInteger());
}else{
dfs(ni.getList());
}
}
}
}
/**
* Your NestedIterator object will be instantiated and called as such:
* NestedIterator i = new NestedIterator(nestedList);
* while (i.hasNext()) v[f()] = i.next();
*/
深度优先搜索+队列
时间O(n)空间O(n)
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List getList();
* }
*/
public class NestedIterator implements Iterator<Integer> {
Deque<Integer> queue = new ArrayDeque<>();
public NestedIterator(List<NestedInteger> nestedList) {
//初始化时便处理元素
dfs(nestedList);
}
@Override
public Integer next() {
//保证调用next前调用hasNext
return hasNext() ? queue.pollFirst() : -1;
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
private void dfs(List<NestedInteger> nestedList){
for(NestedInteger ni:nestedList){
if(ni.isInteger()){
queue.addLast(ni.getInteger());
}else{
dfs(ni.getList());
}
}
}
}
/**
* Your NestedIterator object will be instantiated and called as such:
* NestedIterator i = new NestedIterator(nestedList);
* while (i.hasNext()) v[f()] = i.next();
*/
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List getList();
* }
*/
public class NestedIterator implements Iterator<Integer> {
Deque<NestedInteger> stack = new LinkedList<>();
public NestedIterator(List<NestedInteger> nestedList) {
for(int i=nestedList.size()-1;i>=0;i--){
NestedInteger ni = nestedList.get(i);
stack.push(ni);
}
}
@Override
public Integer next() {
return hasNext() ? stack.pop().getInteger() : -1;
}
@Override
public boolean hasNext() {
if(stack.isEmpty()){
return false;
}else{
NestedInteger ni = stack.peek();
if(ni.isInteger()){
return true;
}else{
ni = stack.pop();
List<NestedInteger> list = ni.getList();
for(int i = list.size()-1;i>=0;i--){
stack.push(list.get(i));
}
return hasNext();
}
}
}
}
/**
* Your NestedIterator object will be instantiated and called as such:
* NestedIterator i = new NestedIterator(nestedList);
* while (i.hasNext()) v[f()] = i.next();
*/
题目描述:
根据逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
提示:
1 <= tokens.length <= 104
tokens[i] 是一个算符(“+”、“-”、“*” 或 “/”),或是在范围 [-200, 200] 内的一个整数
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
栈
时间O(n)空间O(n)
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
int n = tokens.length;
for(int i=0;i<n;i++){
String token = tokens[i];
if(isNumber(token)){
stack.push(Integer.parseInt(token));
}else{
int num2 = stack.pop();
int num1 = stack.pop();
switch(token){
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
default:
stack.push(num1 / num2);
}
}
}
return stack.pop();
}
private boolean isNumber(String token){
return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
}
}
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (String s : tokens) {
if ("+".equals(s)) {
stack.push(stack.pop() + stack.pop());
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
作者:carlsun-2
链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/solution/by-carlsun-2-a0vh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
数组模拟栈
对于一个有效的逆波兰表达式,其长度 n 一定是奇数,且操作数的个数一定比运算符的个数多 11 个,即包含(n+1)/2个操作数和(n-1)/2个运算符
遇到操作数时,栈内元素增加 11 个;遇到运算符时,栈内元素减少 11 个
最坏情况下,(n+1)/2个操作数都在表达式的前面,(n-1)/2个运算符都在表达式的后面,此时栈内元素最多为(n+1)/2个
时间O(n)空间O(n)
class Solution {
public int evalRPN(String[] tokens) {
int n = tokens.length;
int[] stack = new int[(n+1)/2];
int index = -1;
for(int i=0;i<n;i++){
String token = tokens[i];
switch(token){
case "+":
index--;
stack[index] += stack[index + 1];
break;
case "-":
index--;
stack[index] -= stack[index + 1];
break;
case "*":
index--;
stack[index] *= stack[index + 1];
break;
case "/":
index--;
stack[index] /= stack[index + 1];
break;
default:
index++;
stack[index] = Integer.parseInt(token);
}
}
return stack[index];
}
}