前言
当我刷leetcode上第503题:leetcode.cn/problems/ne… 时,发现一句代码的改变,带来的效果差别很大,于是我查找了些资料,在这总和一下。
解此题的代码如下:
class Solution {
public int[] nextGreaterElements(int[] nums) {
//边界判断
if(nums == null || nums.length <= 1){
return new int[]{-1};
}
int size = nums.length;
int[] re = new int[size];
//将结果数组中的所有元素初始化为-1
Arrays.fill(re, -1);
//存放元素值对应的下标
Deque<Integer> stack = new LinkedList<Integer>();
//相当于将两个数组拼接在一起,却不改变原有结构
for(int i = 0; i < size*2; i++){
//当栈不为空且找到比栈顶元素更大值时
while(!stack.isEmpty() && nums[i % size] > nums[stack.peek()]){
re[stack.peek()] = nums[i % size];
stack.pop();
}
stack.push(i % size);
}
return re;
}
}
起初我用的Stack来实现单调栈,也就是:
Stack<Integer> stack = new Stack<>();
这种方法的提交结果是这样:
后根据官方题解,用LinkedList来实现单调栈:
Deque<Integer> stack = new LinkedList<Integer>();
提交结果:
差距很大!!!
分析
Stack具有以下特点:
1. 线程安全,但是效率低。
因为Stack类继承自Vector类,而 Vector类在每个方法中都加了锁:
......
public synchronized void setSize(int newSize){...}
public synchronized int capacity(){...}
public synchronized int size(){...}
public synchronized boolean isEmpty(){...}
......
“加了锁”是指:
Vector类中的每个公共方法都通过同步块或方法声明中的synchronized关键字进行了同步。
通过在每个方法上使用 synchronized,Vector 类确保了在多线程环境中对列表的操作是线程安全的。这意味着在一个时间点,只有一个线程可以执行 Vector 类的任何同步方法。
虽然同步确保了线程安全,但也带来了性能开销。因为同步会限制并发访问,所以可能会导致线程阻塞和等待。
2. 灵活性不好,数据频繁增减效率低,查找数据优势不明显。
Stack类继承自Vector类,而Vector类在内部使用了一个动态数组来存储元素,这意味着Stack的实现是基于数组的。
而数组具有查找快、增删元素慢的特点。