目录
最后一块石头的重量
1046. 最后一块石头的重量 - 力扣(LeetCode)
解法一:暴力模拟(我自己的解法)
class Solution {
public int lastStoneWeight(int[] s) {
int n = s.length;
int left = 0, right = n - 1;
while (left < right) {
Arrays.sort(s);
if (right == left + 1) {
if (s[right] == s[left])
return 0;
else
return Math.max(s[right] - s[left], s[left] - s[right]);
}
if (s[right - 1] == s[right]) {
right -= 2;
} else {
s[right - 1] = s[right - 1] < s[right] ? s[right] - s[right - 1] : s[right - 1] - s[right];
right--;
}
}
return s[left];
}
}
解法二:大根堆模拟
class Solution {
public int lastStoneWeight(int[] s) {
// 创建大根堆
PriorityQueue<Integer> heap = new PriorityQueue<>((a, b) -> b - a);
// 把所有石头放入堆中
for (int x : s) {
heap.offer(x);
}
// 模拟
while (heap.size() > 1) {
int a = heap.poll();
int b = heap.poll();
if (a > b) {
heap.offer(a - b);
}
}
return heap.size() == 1 ? heap.poll() : 0;
}
}
数据流中的第 K 大元素
703. 数据流中的第 K 大元素 - 力扣(LeetCode)
TopK问题:堆(O(nlongK));快速选择算法(O(n))
解法:用堆来解决
- 创建一个大小为k的堆(大根堆or小根堆)
- 循环:
- 依次进堆
- 判断堆的大小是否超过k,如果超过,就把堆顶删去,最后的堆顶即为所求
class KthLargest {
// 创建一个大小为k的小根堆
PriorityQueue<Integer> heap = new PriorityQueue<>();
int _k;
public KthLargest(int k, int[] nums) {
_k = k;
heap = new PriorityQueue<>();
for (int x : nums) {
heap.offer(x);// 进堆
if (heap.size() > _k) {
heap.poll();
}
}
}
public int add(int val) {
heap.offer(val);
if (heap.size() > _k) {
heap.poll();
}
return heap.peek();
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/
前K个高频单词
解法:利用堆来解决topK问题
- 预处理原始字符串数组:用一个哈希表,统计每个单词出现的频次<String>和<String ,int >
- 创建一个大小为k的堆(频次由高到低 - 创建小根堆;频次相同,字典序由低到高 - 创建大根堆)
- 循环:
- 让元素依次进堆
- 判断:heap.size()>k 则删去堆顶
- 提取结果
class Solution {
public List<String> topKFrequent(String[] w, int k) {
// 统计每个单词出现的频次
Map<String, Integer> hash = new HashMap<>();
for (String s : w) {
hash.put(s, hash.getOrDefault(s, 0) + 1);//
}
// 创建大小为k的堆
PriorityQueue<Pair<String, Integer>> heap = new PriorityQueue<>((a, b) -> {
return a.getValue().equals(b.getValue()) ? b.getKey().compareTo(a.getKey()) : a.getValue() - b.getValue();
});
// topK主逻辑:
for (Map.Entry<String, Integer> e : hash.entrySet()) {
heap.offer(new Pair<>(e.getKey(), e.getValue()));
if (heap.size() > k)
heap.poll();
}
// 提取结果
List<String> ret = new ArrayList<>();
while (!heap.isEmpty()) {
ret.add(heap.poll().getKey());
}
// 逆序数组
Collections.reverse(ret);
return ret;
}
}
数据流的中位数
解法一:直接sort(超时)
解法二:插入排序的思想(可能超时)
解法三:大小堆来维护数据流的中位数
分类讨论:
- m==n:
- num<=x||m==0 -> left;
- num>x -> right;right堆顶进入left;
- m>n -> m==n+1:
- num<=x -> left;left堆顶进入right;
- num>x -> right;
class MedianFinder {
PriorityQueue<Integer> left;
PriorityQueue<Integer> right;
public MedianFinder() {
left = new PriorityQueue<Integer>((a, b) -> b - a);
right = new PriorityQueue<Integer>((a, b) -> a - b);
}
public void addNum(int num) {
if (left.size() == right.size()) {
if (left.isEmpty() || num <= left.peek())
left.offer(num);
else {
right.offer(num);
left.offer(right.poll());
}
} else {
if (num <= left.peek()) {
left.offer(num);
right.offer(left.poll());
} else {
right.offer(num);
}
}
}
public double findMedian() {
if (left.size() == right.size())
return (left.peek() + right.peek()) / 2.0;
else
return left.peek();
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/