栈
20.有效的括号
思考:用栈存左括号,如果遇到右括号就弹出栈,出栈的左括号和右括号匹配就true否则false
记录:需要二刷
class Solution {
public boolean isValid(String s) {
Stack<Character> left = new Stack<>();
for(char c : s.toCharArray()){
if(c == '(' || c == '[' || c =='{'){
left.push(c);
}else{
if(left.isEmpty()){
return false;
}else{
if(left.pop() != findLeft(c)){
return false;
}
}
}
}
return left.isEmpty()? true:false;
}
char findLeft(Character right){
if(right == ')'){
return '(';
}else if(right == '}'){
return '{';
}else{
return '[';
}
}
}
155.最小栈
思考:用两个栈存储,最大栈就是基础的push、pop、peek操作。最小栈需要判断,每次push只存最小元素,如果当前元素小于最小元素,就存入,如果大于就把最小元素再存一次
记录:需要二刷
class MinStack {
Stack<Integer> min;
Stack<Integer> max;
public MinStack() {
min = new Stack<>();
max = new Stack<>();
}
public void push(int val) {
if(min.isEmpty() || min.peek()>=val){
min.push(val);
}else{
min.push(min.peek());
}
max.push(val);
}
public void pop() {
max.pop();
min.pop();
}
public int top() {
return max.peek();
}
public int getMin() {
return min.peek();
}
}
394.字符串编码
思考:用两个栈:数字、括号中路径
- 如果当前字符是数字,就记录数字(先不存进栈,防止是十位、百位这种)
- 遇到左括号,证明前面数字记录完毕,把数字存入数字栈。把前面的字符res全部存入字符栈。然后初始化数字和字符res,这样保证括号后面的重新入栈
- 然后括号里面的依次记录,如果是字符直接加入res(已经初始化过了)
- 遇到右括号,把数字弹出,把字符弹出,在弹出的字符res上依次添加刚刚括号里的记录
记录:需要二刷
class Solution {
public String decodeString(String s) {
StringBuilder res = new StringBuilder();
Stack<Integer> num = new Stack<>();
Stack<StringBuilder> track = new Stack<>();
int numTrack = 0;
for(int i = 0;i < s.length();i++){
char c = s.charAt(i);
if(Character.isDigit(c)){
numTrack = numTrack * 10 + c - '0';
}else if(c == '['){
num.push(numTrack);
track.push(res);
res = new StringBuilder();
numTrack = 0;
}else if(c == ']'){
int curNum = num.pop();
StringBuilder curString = track.pop();
for(int j = 0;j < curNum;j++){
curString.append(res);
}
res = curString;
}else{
res.append(c);
}
}
return res.toString();
}
}
739.每日温度
思考:用栈存储气温较大值。遍历整个气温数组,注意从后往前,这样可获取当日往后的气温作为先验数据。每次都将栈中气温和当日气温比较,如果栈中气温小于当日,证明气温下降,就pop出去,注意这里用while可以确保栈中每个气温都与当日比较。然后将栈中存留的(代表气温上升的)存入结果集,最后当日的气温push进栈。
注意这里栈中存的是索引,方便对结果集存储
记录:需要二刷
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] res = new int[temperatures.length];
Stack<Integer> s = new Stack<>();
for(int i = temperatures.length-1;i >= 0;i--){
while(!s.isEmpty() && temperatures[s.peek()] <= temperatures[i]){
s.pop();
}
res[i] = s.isEmpty() ? 0 : (s.peek()-i);
s.push(i);
}
return res;
}
}
84.柱状图中最大的矩阵
思考:找到一个柱子 heights[p]
大于或等于当前柱子 heights[i]
时,知道它不可能是我们要找的"左侧第一个小于当前高度的柱子"。可以直接跳到 left[p]
(即柱子p左侧的第一个小于p的柱子),而不需要一个一个向左检查。这是因为:
- 如果
heights[p] >= heights[i]
,那么p
左边的所有高度大于等于heights[p]
的柱子也一定大于等于heights[i]
- 所以我们可以直接跳到
left[p]
,这是一个已经计算好的、p
左侧第一个小于heights[p]
的位置
记录:需要二刷
class Solution {
public int largestRectangleArea(int[] heights) {
int[] left = new int[heights.length];
int[] right = new int[heights.length];
for(int i = 0;i < heights.length;i++){
int p = i-1;
while(p >= 0 && heights[p] >= heights[i]){
p = left[p];
}
left[i] = p;
}
for(int i = heights.length-1;i >= 0;i--){
int p = i+1;
while(p < heights.length && heights[p] >= heights[i]){
p = right[p];
}
right[i] = p;
}
int res = 0;
for(int i = 0;i < heights.length;i++){
int width = right[i] - left[i] - 1;
int area = heights[i] * width;
res = Math.max(area,res);
}
return res;
}
}
堆
215.数组中的第K个最大元素
思考:排序好的数组,第k个最大的就是数组个数-k,秒
记录:不需要二刷
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length-k];
}
}
347.前K个高频元素
思考:用优先级队列存哈希值,按照大小比较,当队列中元素大于k就拉出来,否则就存进去,最后把队列里元素的key拿出来放到结果里
记录:需要二刷
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> numToCount = new HashMap<>();
for(int i = 0;i < nums.length;i++){
numToCount.put(nums[i],numToCount.getOrDefault(nums[i],0)+1);
}
PriorityQueue<Map.Entry<Integer,Integer>> pq = new PriorityQueue<>(
(hm1,hm2)->{
return hm1.getValue().compareTo(hm2.getValue());
}
);
for(Map.Entry<Integer,Integer> hm : numToCount.entrySet()){
pq.offer(hm);
if(pq.size() > k){
pq.poll();
}
}
int[] res = new int[k];
for(int i = 0;i < k;i++){
res[i] = pq.poll().getKey();
}
return res;
}
}
295.数据流的中位数
思考:拿两个优先级队列分别表示小和大,每次添加元素时保持两个队列差不多长,如果给小队列添加元素,就把小的里面最大值弹出给大队列,大队列同理。返回中位数即返回小/大中多的元素或平均值
记录:需要二刷
class MedianFinder {
PriorityQueue<Integer> min;
PriorityQueue<Integer> max;
public MedianFinder() {
min = new PriorityQueue<>();
max = new PriorityQueue<>((a,b)->{return b-a;});
}
public void addNum(int num) {
if(min.size() >= max.size()){
min.offer(num);
max.offer(min.poll());
}else{
max.offer(num);
min.offer(max.poll());
}
}
public double findMedian() {
if(min.size() > max.size()){
return min.peek();
}else if(min.size() < max.size()){
return max.peek();
}else{
return (min.peek() + max.peek())/2.0;
}
}
}