Leetcode 239. 滑动窗口最大值 Sliding Window Maximum
最开始我用暴力解法超时了,结果显示:Time Limit Exceeded,42 / 51 testcases passed
暴力解法时间复杂度为:O(n) = (n * k)
代码如下,相当于每次right++(+1)后窗口内元素都要进行for循环,许多数也被重复遍历:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 1 && k == 1) {
return new int[] {1};
}
int n = nums.length;
int[] res = new int[n - k + 1];
// List<Integer> list = new ArrayList<>();
int left = 0, right = k - 1;
int maxVal = Integer.MIN_VALUE;
int count = 0;
while (right < n) {
maxVal = Integer.MIN_VALUE;
for (int i = left; i <= right; i++) {
maxVal = Math.max(nums[i], maxVal);
}
res[count++] = maxVal;
list.add(maxVal);
right++;
left++;
}
}
}
优化方法:
1)使用单调队列。每次pop出一位元素,然后获取目前窗口的最大值,最后push一位元素到队列中;
2)每次在push元素时,push的元素的之前的元素都比push的元素小的话,都移出队列,保证最大值元素在队列中首位。
//实现单调队列
class MonotonicQueue {
LinkedList<Integer> queue = new LinkedList<>();
public void push(int n) {
//如果加入队列中的前一个数小于n的话,移除队列
//循环知道队列首位元素为最大值
while (!queue.isEmpty() && queue.getLast() < n) {
queue.pollLast();
}
queue.addLast(n);
}
public int max() {
return queue.getFirst();
}
public void pop(int n) {
if (n == queue.getFirst()) {
queue.pollFirst();
}
}
}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
MonotonicQueue queue = new MonotonicQueue();
List<Integer> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (i < k - 1) {
//添足窗口元素
queue.push(nums[i]);
} else {
//向前移动窗口
queue.push(nums[i]);
//获取当前窗口的最大值
res.add(queue.max());
//移除窗口中首位元素
queue.pop(nums[i - k + 1]);
}
}
int[] arr = new int[res.size()];
int index = 0;
for (int val : res) {
arr[index++] = val;
}
return arr;
}
}
Leetcode 347. 前 K 个高频元素 Top K Frequent Elements
1)使用HashMap存储所有元素,键值对key为元素值,value为相同元素出现的频次。当遇到相同key时,次数+1;
2)使用PriorityQueue 遍历将hashmap中的键值对根据出现的频次按照从小到大的顺序排列;
3)通过倒序遍历数组,获取队列中的元素;
4)PriorityQueue底层实现是堆,这题要用小顶堆,因为统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
//记录每个元素重复的频次
for (int val : nums) {
map.put(val, map.getOrDefault(val, 0) + 1);
}
//使用优先级队列获得前k个元素
PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>((entry1,entry2) -> {
return entry1.getValue().compareTo(entry2.getValue());
});
for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
//遍历hashmap,并且将键值对放入队列中
pq.offer(entry);
if (pq.size() > k) {
pq.poll();
}
}
//获取前k个
int[] res = new int[k];
for (int i = k - 1; i >= 0; i--) {
res[i] = pq.poll().getKey();
}
return res;
}
}