7.7 栈 堆
This commit is contained in:
parent
730f26f950
commit
8c8f0d0b20
@ -17,6 +17,7 @@ package binary_search;
|
||||
//二刷不会
|
||||
public class FindMedianSortedArrays {
|
||||
|
||||
|
||||
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
|
||||
int length1 = nums1.length, length2 = nums2.length;
|
||||
int totalLength = length1 + length2;
|
||||
|
@ -15,8 +15,10 @@ import java.util.PriorityQueue;
|
||||
|
||||
* 链接:https://leetcode.cn/problems/kth-largest-element-in-an-array/
|
||||
*/
|
||||
//二刷不会 背一下堆的创建 快速选择
|
||||
public class FindKthLargest {
|
||||
//完全填满堆再删除元素 最大堆
|
||||
|
||||
//完全填满堆再删除元素 最大堆 O(nlogn)
|
||||
public int findKthLargest1(int[] nums, int k) {
|
||||
PriorityQueue<Integer>maxheap=new PriorityQueue<>(Comparator.reverseOrder());
|
||||
for (int num : nums) {
|
||||
@ -28,6 +30,7 @@ public class FindKthLargest {
|
||||
return maxheap.peek();
|
||||
}
|
||||
//使用最小堆来存储前 k 个最大的元素。堆顶元素是 k 个最大元素中的最小值。这样,堆的大小始终保持为 k。当堆的大小大于 k 时,弹出堆顶元素。最终堆顶元素就是第 k 大的元素。不需要完全填满堆再删除元素:
|
||||
// O(nlogk)
|
||||
public int findKthLargest2(int[] nums, int k) {
|
||||
// 使用最小堆
|
||||
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
|
||||
@ -47,7 +50,7 @@ public class FindKthLargest {
|
||||
// 返回堆顶元素,即为第 k 大的元素
|
||||
return minHeap.peek();
|
||||
}
|
||||
//快速选择
|
||||
//快速选择 O(n)
|
||||
public int quickselect(int[] nums, int l, int r, int k) {
|
||||
// 当区间内只有一个元素时,直接返回该元素
|
||||
if (l >= r) {
|
||||
|
@ -19,17 +19,16 @@ import java.util.PriorityQueue;
|
||||
* 链接:https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/
|
||||
*/
|
||||
//有思路 但是超出时间限制,需要优化
|
||||
//二刷不会优化
|
||||
public class KSmallestPairs {
|
||||
|
||||
/**
|
||||
* 可以把所有可能的组合看作一个虚拟的二维矩阵:
|
||||
*
|
||||
* 行代表 nums1[i]
|
||||
* 列代表 nums2[j]
|
||||
* 每个点 (i,j) 对应的值是 nums1[i] + nums2[j]
|
||||
* 这个矩阵的特点是:从左到右、从上到下递增,因为两个数组都升序。
|
||||
*
|
||||
* 我们不需要全部生成矩阵,而是只维护当前“最小的候选对”,类似 Dijkstra 算法或 BFS:
|
||||
*
|
||||
* 初始时,把前 k 行的第一列(即 (nums1[i], nums2[0]))放入堆中。因为后面的列比前面的大,我们先选列头。
|
||||
* 每次弹出堆顶(最小的和),把它加入结果列表。
|
||||
* 如果该对还有下一列(即 (i, j+1) 存在),就把 (i, j+1) 加入堆,作为下一个候选。
|
||||
@ -45,26 +44,25 @@ public class KSmallestPairs {
|
||||
// 边界处理:任一数组为空 或 k==0,直接返回空结果
|
||||
if (nums1.length == 0 || nums2.length == 0 || k == 0) return res;
|
||||
|
||||
// 小顶堆,存储的是每对数的索引 [i, j],按对应的和升序排列
|
||||
// 小顶堆,存储的是每对数的索引 [i, j],按对应的和 升序排列
|
||||
PriorityQueue<int[]> minHeap = new PriorityQueue<>(
|
||||
(a, b) -> nums1[a[0]] + nums2[a[1]] - nums1[b[0]] - nums2[b[1]]
|
||||
);
|
||||
|
||||
// 初始化:将 nums1 的前 k 个元素与 nums2[0] 组成的数对放入堆中
|
||||
// 因为只推进列,所以只需要每一行的第一个元素
|
||||
// 初始:把每一行的第 0 列(最多 k 行)加入堆
|
||||
for (int i = 0; i < Math.min(nums1.length, k); i++) {
|
||||
minHeap.offer(new int[]{i, 0}); // i 表示 nums1 的索引,j=0 是固定的起点
|
||||
}
|
||||
|
||||
// 取出堆顶最小的数对,直到取满 k 个或者堆空为止
|
||||
// 取最小的 k 对
|
||||
while (k-- > 0 && !minHeap.isEmpty()) {
|
||||
int[] pos = minHeap.poll(); // 当前最小的数对在 nums1[pos[0]], nums2[pos[1]]
|
||||
int i = pos[0], j = pos[1];
|
||||
int[] idx = minHeap.poll();
|
||||
int i = idx[0], j = idx[1];
|
||||
|
||||
// 把数对值加入结果集
|
||||
res.add(List.of(nums1[i], nums2[j]));
|
||||
|
||||
// 如果当前数对还有下一列,就推进下一列(仍然在第 i 行)
|
||||
// 推入同一行的下一列 若这一行所有可能的列都已被消费完了,就不再往堆里推新的 (i, j+1)
|
||||
if (j + 1 < nums2.length) {
|
||||
minHeap.offer(new int[]{i, j + 1});
|
||||
}
|
||||
|
@ -14,10 +14,46 @@ import java.util.PriorityQueue;
|
||||
|
||||
* 链接:https://leetcode.cn/problems/top-k-frequent-elements/
|
||||
*/
|
||||
// 二刷不会
|
||||
public class TopKFrequent {
|
||||
|
||||
public int[] topKFrequent(int[] nums, int k) {
|
||||
HashMap<Integer,Integer> map=new HashMap<>();
|
||||
int cnt=0;
|
||||
PriorityQueue<int[]> minHeap=new PriorityQueue<>( //小根堆
|
||||
(a,b) -> a[1]-b[1]
|
||||
);
|
||||
int[] temp;
|
||||
int[] res=new int[k];
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
int cur=nums[i];
|
||||
map.put(cur, map.getOrDefault(cur,0)+1);
|
||||
}
|
||||
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||
if(cnt<k){
|
||||
minHeap.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
cnt++;
|
||||
}else {
|
||||
temp=minHeap.peek();
|
||||
if(entry.getValue()>temp[1]) {
|
||||
minHeap.poll();
|
||||
minHeap.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
}
|
||||
}
|
||||
}
|
||||
cnt=0;
|
||||
for (int[] ints : minHeap) {
|
||||
res[cnt++]=ints[0];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public int[] topKFrequent2(int[] nums, int k) {
|
||||
HashMap<Integer,Integer>map=new HashMap<>();
|
||||
PriorityQueue<int[]> minHeap = new PriorityQueue<>(
|
||||
PriorityQueue<int[]> maxHeap = new PriorityQueue<>( //大根堆
|
||||
(a, b) -> b[1] - a[1]);
|
||||
int[] res=new int[k];
|
||||
int i=0;
|
||||
@ -28,11 +64,11 @@ public class TopKFrequent {
|
||||
map.put(num,map.get(num)+1);
|
||||
}
|
||||
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
|
||||
minHeap.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
maxHeap.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
}
|
||||
while (!minHeap.isEmpty()) {
|
||||
while (!maxHeap.isEmpty()) {
|
||||
if(i<k)
|
||||
res[i++] = minHeap.poll()[0];
|
||||
res[i++] = maxHeap.poll()[0];
|
||||
else break;
|
||||
}
|
||||
return res;
|
||||
|
@ -14,8 +14,28 @@ import java.util.Deque;
|
||||
* 链接:https://leetcode.cn/problems/daily-temperatures/
|
||||
*/
|
||||
//第一次做没想到怎么利用栈
|
||||
//二刷会做
|
||||
public class DailyTemperatures {
|
||||
public int[] dailyTemperatures(int[] temperatures) {
|
||||
int n = temperatures.length;
|
||||
int[] ans = new int[n]; // 默认全 0,不用后面再填
|
||||
Deque<Integer> stack = new ArrayDeque<>();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
// 只要栈不空,且当前温度更高,就把栈顶结算出来
|
||||
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
|
||||
int prev = stack.pop();
|
||||
ans[prev] = i - prev;
|
||||
}
|
||||
stack.push(i);
|
||||
}
|
||||
|
||||
// 剩下的索引对应的 ans 已经是 0 了(Java 数组默认值)
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
public int[] dailyTemperatures1(int[] temperatures) {
|
||||
// 结果数组,初始化为全零
|
||||
int[] result = new int[temperatures.length];
|
||||
|
||||
|
@ -3,6 +3,7 @@ package stack;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* 题目: 394. 字符串解码 (decodeString)
|
||||
@ -18,8 +19,10 @@ import java.util.LinkedList;
|
||||
* 链接:https://leetcode.cn/problems/search-in-rotated-sorted-array/
|
||||
*/
|
||||
//不会 有难度!
|
||||
//二刷不会
|
||||
public class DecodeString {
|
||||
//s = "3[a]2[bc]" "3[a2[c]]"
|
||||
|
||||
// s = "3[a]2[bc]" "3[a2[c]]"
|
||||
public String decodeString(String s) {
|
||||
// 定义两个栈
|
||||
Deque<Integer> countStack = new LinkedList<>();
|
||||
|
@ -16,7 +16,10 @@ import java.util.HashMap;
|
||||
*
|
||||
* 链接:https://leetcode.cn/problems/valid-parentheses/
|
||||
*/
|
||||
//二刷会做
|
||||
public class IsValid {
|
||||
|
||||
|
||||
public boolean isValid(String s) {
|
||||
// 如果长度为奇数,直接返回 false
|
||||
int sz = s.length();
|
||||
|
@ -16,94 +16,151 @@ import java.util.Deque;
|
||||
* 链接:https://leetcode.cn/problems/largest-rectangle-in-histogram/
|
||||
*/
|
||||
//初见不会
|
||||
//二刷不会
|
||||
public class LargestRectangleArea {
|
||||
//暴力法 依次遍历柱形的高度,对于每一个高度分别向两边扩散,求出以当前高度为矩形的最大宽度多少。
|
||||
public int largestRectangleArea1(int[] heights) {
|
||||
int len = heights.length;
|
||||
// 特判
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
// public int largestRectangleArea(int[] heights) {
|
||||
// int len=heights.length;
|
||||
// int[] leftIndex=new int[len],rightIndex=new int[len];
|
||||
// leftIndex[0]=-1;
|
||||
// rightIndex[len-1]=len;
|
||||
// for (int i = 1; i < len; i++) {
|
||||
// int cur=heights[i];
|
||||
// int left=i-1;
|
||||
// //向左找到第一个小于cur的index
|
||||
// while (left>=0 && cur<=heights[left]){
|
||||
// left=leftIndex[left];
|
||||
// }
|
||||
// leftIndex[i]=left;
|
||||
// }
|
||||
// for (int i = len-2; i >=0 ; i--) {
|
||||
// int cur=heights[i];
|
||||
// int right=i+1;
|
||||
// while (right<len && cur<=heights[right])
|
||||
// right=rightIndex[right];
|
||||
// rightIndex[i]=right;
|
||||
// }
|
||||
// int max=Integer.MIN_VALUE;
|
||||
// for (int i = 0; i < len; i++) {
|
||||
// max=Math.max(max,(rightIndex[i]-leftIndex[i]-1)*heights[i]);
|
||||
// }
|
||||
// return max;
|
||||
// }
|
||||
|
||||
// 找左边最后 1 个大于等于 heights[i] 的下标
|
||||
int left = i;
|
||||
int curHeight = heights[i];
|
||||
while (left > 0 && heights[left - 1] >= curHeight) {
|
||||
left--;
|
||||
}
|
||||
|
||||
// 找右边最后 1 个大于等于 heights[i] 的索引
|
||||
int right = i;
|
||||
while (right < len - 1 && heights[right + 1] >= curHeight) {
|
||||
right++;
|
||||
}
|
||||
|
||||
int width = right - left + 1;
|
||||
res = Math.max(res, width * curHeight);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//动态规划 暴力解优化
|
||||
public int largestRectangleArea2(int[] heights) {
|
||||
int size = heights.length;
|
||||
int[] minLeftIndex = new int[size];
|
||||
int[] minRightIndex = new int[size];
|
||||
|
||||
// 记录每个柱子左边第一个小于该柱子的下标
|
||||
minLeftIndex[0] = -1; // 初始化,防止死循环
|
||||
for (int i = 1; i < size; i++) {
|
||||
int t = i - 1;
|
||||
// 不断向左寻找,直到找到第一个小于当前柱子的柱子
|
||||
while (t >= 0 && heights[t] >= heights[i]) {
|
||||
t = minLeftIndex[t]; // 更新为左边第一个小于当前柱子的下标
|
||||
}
|
||||
minLeftIndex[i] = t;
|
||||
}
|
||||
|
||||
// 记录每个柱子右边第一个小于该柱子的下标
|
||||
minRightIndex[size - 1] = size; // 初始化,防止死循环
|
||||
for (int i = size - 2; i >= 0; i--) {
|
||||
int t = i + 1;
|
||||
// 不断向右寻找,直到找到第一个小于当前柱子的柱子
|
||||
while (t < size && heights[t] >= heights[i]) {
|
||||
t = minRightIndex[t]; // 更新为右边第一个小于当前柱子的下标
|
||||
}
|
||||
minRightIndex[i] = t;
|
||||
}
|
||||
|
||||
// 计算最大矩形面积
|
||||
int result = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
int width = minRightIndex[i] - minLeftIndex[i] - 1;
|
||||
int area = heights[i] * width;
|
||||
result = Math.max(result, area);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//单调栈
|
||||
/**
|
||||
* 暴力法
|
||||
* 对于每一个柱子 i,当做“最低高度”,向左扫描找到第一个高度比它小的位置 left,
|
||||
* 向右扫描找到第一个比它小的位置 right,那么以它为高的最大矩形宽度就是 right–left–1,面积就是 heights[i] * (right - left - 1)。
|
||||
*/
|
||||
// public int largestRectangleArea1(int[] heights) {
|
||||
// int len = heights.length;
|
||||
// // 特判
|
||||
// if (len == 0) {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// int res = 0;
|
||||
// for (int i = 0; i < len; i++) {
|
||||
//
|
||||
// // 找左边最后 1 个大于等于 heights[i] 的下标
|
||||
// int left = i;
|
||||
// int curHeight = heights[i];
|
||||
// while (left > 0 && heights[left - 1] >= curHeight) {
|
||||
// left--;
|
||||
// }
|
||||
//
|
||||
// // 找右边最后 1 个大于等于 heights[i] 的索引
|
||||
// int right = i;
|
||||
// while (right < len - 1 && heights[right + 1] >= curHeight) {
|
||||
// right++;
|
||||
// }
|
||||
//
|
||||
// int width = right - left + 1;
|
||||
// res = Math.max(res, width * curHeight);
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 动态规划 暴力解优化
|
||||
// * 预先为每根柱子 i 计算出:
|
||||
// * minLeftIndex[i]:右边第一个小于它的柱子的下标
|
||||
// * minRightIndex[i]:左边第一个小于它的柱子的下标
|
||||
// * 计算完后,对于每个 i,它能扩展的最大宽度就是 (minRightIndex[i] - minLeftIndex[i] - 1),面积同理用高度乘宽度即可。
|
||||
//
|
||||
// */
|
||||
// public int largestRectangleArea2(int[] heights) {
|
||||
// int size = heights.length;
|
||||
// int[] minLeftIndex = new int[size];
|
||||
// int[] minRightIndex = new int[size];
|
||||
//
|
||||
// // 记录每个柱子左边第一个小于该柱子的下标
|
||||
// minLeftIndex[0] = -1; // 初始化,防止死循环
|
||||
// for (int i = 1; i < size; i++) {
|
||||
// int t = i - 1;
|
||||
// // 不断向左寻找,直到找到第一个小于当前柱子的柱子
|
||||
// while (t >= 0 && heights[t] >= heights[i]) {
|
||||
// t = minLeftIndex[t]; // 更新为左边第一个小于当前柱子的下标
|
||||
// }
|
||||
// minLeftIndex[i] = t;
|
||||
// }
|
||||
//
|
||||
// // 记录每个柱子右边第一个小于该柱子的下标
|
||||
// minRightIndex[size - 1] = size; // 初始化,防止死循环
|
||||
// for (int i = size - 2; i >= 0; i--) {
|
||||
// int t = i + 1;
|
||||
// // 不断向右寻找,直到找到第一个小于当前柱子的柱子
|
||||
// while (t < size && heights[t] >= heights[i]) {
|
||||
// t = minRightIndex[t]; // 更新为右边第一个小于当前柱子的下标
|
||||
// }
|
||||
// minRightIndex[i] = t;
|
||||
// }
|
||||
//
|
||||
// // 计算最大矩形面积
|
||||
// int result = 0;
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// int width = minRightIndex[i] - minLeftIndex[i] - 1;
|
||||
// int area = heights[i] * width;
|
||||
// result = Math.max(result, area);
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* 单调栈解法思路:
|
||||
* - 使用一个栈保存柱子的索引,栈内对应的高度单调递增。
|
||||
* - 遍历每个柱子 i:
|
||||
* - 当当前柱子高度小于栈顶高度时,说明以栈顶柱子为高的矩形在 i 处结束:
|
||||
* pop 出栈顶 prev,计算宽度为 i - stack.peek() - 1,面积 = heights[prev] * width。
|
||||
* - 重复上述步骤,直到栈空或栈顶高度不超过当前高度。
|
||||
* - 将当前索引 i 压入栈中。
|
||||
* - 遍历结束后,栈中仍有索引,依次弹出并计算:
|
||||
* 宽度 = n - stack.peek() - 1。
|
||||
* - 时间复杂度 O(n),空间复杂度 O(n)。
|
||||
*/
|
||||
public int largestRectangleArea(int[] heights) {
|
||||
Deque<Integer>stack=new ArrayDeque<>();
|
||||
int max=Integer.MIN_VALUE;
|
||||
int n = heights.length;
|
||||
Deque<Integer> stack = new ArrayDeque<>();
|
||||
// 先放一个哨兵,方便计算宽度
|
||||
stack.push(-1);
|
||||
for (int i = 0; i < heights.length; i++) {
|
||||
while(stack.size()>=2 && heights[i]<heights[stack.peek()]){
|
||||
int cur=stack.pop();
|
||||
int width=i-stack.peek()-1;
|
||||
if(max<width*heights[cur])
|
||||
max=width*heights[cur];
|
||||
int maxArea = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
// 当前高度小于栈顶高度时,栈顶矩形结束
|
||||
while (stack.peek() != -1 && heights[i] < heights[stack.peek()]) {
|
||||
int prev = stack.pop(); // 栈顶索引
|
||||
int width = i - stack.peek() - 1; // 计算以 heights[prev] 为高的宽度
|
||||
maxArea = Math.max(maxArea, heights[prev] * width);
|
||||
}
|
||||
stack.push(i);
|
||||
}
|
||||
while(stack.size()>=2){
|
||||
int cur=stack.pop();
|
||||
int width=heights.length-stack.peek()-1;
|
||||
if(max<width*heights[cur])
|
||||
max=width*heights[cur];
|
||||
// 处理剩余索引
|
||||
while (stack.peek() != -1) {
|
||||
int prev = stack.pop();
|
||||
int width = n - stack.peek() - 1;
|
||||
maxArea = Math.max(maxArea, heights[prev] * width);
|
||||
}
|
||||
return max;
|
||||
return maxArea;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package stack;
|
||||
package 实现类功能;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
@ -15,6 +15,7 @@ import java.util.Stack;
|
||||
*
|
||||
* 链接:https://leetcode.cn/problems/min-stack/description/
|
||||
*/
|
||||
//二刷不会
|
||||
public class MinStack {
|
||||
|
||||
private Stack<Integer> stack; // 主栈
|
Loading…
x
Reference in New Issue
Block a user