[LeetCode/PriorityQueue/Java]LeetCode之Heap(PriorityQueue)题解(Java)

PriorityQueue(优先队列)基础知识和常用方法: [PriorityQueue/Java]PriorityQueue(优先队列)

215. Kth Largest Element in an Array

一、题目

Problem Description:
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:
Input: [3,2,1,5,6,4] and k = 2
Output: 5

Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.

二、题解

Approach #1 : Sorting
Time complexity : O ( N l o g N ) O(NlogN) O(NlogN)
Space complexity : O ( 1 ) O(1) O(1)

//Sorting
//Time complexity : O(NlogN);  Space complexity : O(1)
class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);//按数组nums中的元素值顺序排序
		return nums[nums.length - k];
    }
}

Approach #2 : Heap(PriorityQueue)
Time complexity : O ( N l o g k ) O(Nlogk) O(Nlogk)
Space complexity : O ( k ) O(k) O(k)

//Heap(PriorityQueue)
//Time complexity : O(Nlogk);  Space complexity : O(k)
class Solution {
    public int findKthLargest(int[] nums, int k) {
		Queue<Integer> queue = new PriorityQueue<>();//默认初始化为最小优先队列
		for(int num : nums){
			queue.add(num);//将指定元素插入到此优先队列中
			//优先队列中留下k个元素值较大的元素,即queue.size()=k
			if(queue.size() > k){
				queue.poll();//获取并删除此队列的首元素
			}
		}
		return queue.peek();//获取但不删除此队列的首元素
    }
}

973. K Closest Points to Origin

一、题目

Problem Description:
We have a list of points on the plane. Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:
Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation:
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].

Example 2:
Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

Note:

  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000

二、题解

Approach #1 : Sorting
Time complexity : O ( N l o g N ) O(NlogN) O(NlogN)
Space complexity : O ( 1 ) O(1) O(1)

//Sorting
//Time complexity : O(NlogN); Space complexity : O(1)
//This solution is sorting the all points by their distance to the origin point directly, then get the top k closest points. 
class Solution {
    public int[][] kClosest(int[][] points, int K) {
		/*
		//传统的比较器定义
		Comparator<int[]> cmp = new Comparator<>(){
			@Override
			public int compare(int[] p1, int[] p2){
 				return p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1];//正序
			}
		};
		Arrays.sort(points, cmp);//根据比较器对数组进行顺序排序
		*/
		//lambda表达式定义比较器
		Arrays.sort(points, (p1, p2) -> (p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1]));//正序
		return Arrays.copyOfRange(points, 0, K);//复制points数组索引为0~K-1的元素返回一个新数组
    }
}

Approach #2 : Heap(PriorityQueue)
Time complexity : O ( N l o g K ) O(NlogK) O(NlogK)
Space complexity : O ( K ) O(K) O(K)

//Heap(PriorityQueue)
//Time complexity : O(NlogK); Space complexity : O(K)
class Solution {
    public int[][] kClosest(int[][] points, int K) {
		/*
		//传统的比较器定义
		Comparator<int[]> cmp = new Comparator<>(){
			@Override
			public int compare(int[] p1, int[] p2){
 				return p2[0] * p2[0] + p2[1] * p2[1] - p1[0] * p1[0] - p1[1] * p1[1];//倒序
			}
		};
        Queue<int[]> queue = new PriorityQueue<>(cmp);//最大优先队列
		*/
		//lambda表达式定义比较器
		Queue<int[]> queue = new PriorityQueue<>((p1, p2) -> (p2[0] * p2[0] + p2[1] * p2[1] - p1[0] * p1[0] - p1[1] * p1[1]));//倒序,最大优先队列
		for(int[] point : points){
			queue.offer(point);
			//优先队列中留下K个欧式距离较小的坐标点,即queue.size()=K
			if(queue.size() > K){
				queue.poll();//最大优先队列,大根堆,欧式距离最大的坐标点出队
			}
		}
		int[][] resNums = new int[K][2];//定义一个K个坐标点的二维返回数组
		//遍历优先队列,将坐标点出队至二维数组
		for(int i = 0; i < K; i++){
			resNums[i] = queue.poll();
		}
		return resNums;
    }
}

—— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— ——

378. Kth Smallest Element in a Sorted Matrix

一、题目

Problem Description:
Given a n*n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element in the sorted order, not the kth distinct element.

Example:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
return 13.

Note:
You may assume k is always valid, 1 ≤ k ≤ n 2 n^2 n2.

二、题解

Approach #1 : Heap(PriorityQueue)
普通解题思路:
依次遍历n*n矩阵各个元素,并将其插入至k个容量的最大优先队列。优先队列中始终留下的是k个元素值较小的元素。

//Heap(PriorityQueue)
//Time complexity : O(Nlogk);  Space complexity : O(k)
class Solution {
    public int kthSmallest(int[][] matrix, int k) {
		//lambda表达式定义比较器
        Queue<Integer> queue = new PriorityQueue<>((num1, num2) -> (num2 - num1));//倒序,最大优先队列
		//遍历matrix中的各个元素,并入队
        for(int[] nums : matrix){
			for(int num : nums){
				queue.offer(num);
                //优先队列中留下k个元素值较小的元素,即queue.size()=k
				if(queue.size() > k){
					queue.poll();//最大优先队列,大根堆,元素值最大的元素出队
				}
			}
		}						
		return queue.peek();
    }
}

注:
此解法这样书写更直观,更利于理解,但由于解题过程中没有用到"each of the rows and columns are sorted in ascending order"这个条件,因此针对此条件可以做以下进一步的优化。

优化解题思路:
1.Build a minHeap of elements from the first row.
2.Do the following operations k-1 times :
Every time when you poll out the root(Top Element in Heap), you need to know the row number and column number of that element(so we can create a tuple class here), replace that root with the next element from the same column.

//Heap(PriorityQueue)
//Time complexity : O(klogk);  Space complexity : O(k)
class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        Queue<Tuple> queue = new PriorityQueue<>();//顺序,最小优先队列
		int n = matrix.length;
		//1.Build a minHeap of elements from the first row.
		for(int i = 0; i < n; i++){
			queue.offer(new Tuple(0, i, matrix[0][i]));
		}
		/*2.Do the following operations k-1 times :
		Every time when you poll out the root(Top Element in Heap), 
		you need to know the row number and column number of that element(so we can create a tuple class here), 
		replace that root with the next element from the same column.
		*/
		for(int i = 0; i < k-1; i++){
			Tuple t = queue.poll();
			if(t.x == n-1) continue;
			queue.offer(new Tuple(t.x+1, t.y, matrix[t.x+1][t.y]));
		}
		return queue.poll().val;
    }
}
class Tuple implements Comparable<Tuple>{
	int x, y, val;
	public Tuple(int x, int y, int val){
		this.x = x;
		this.y = y;
		this.val = val;
	}
	@Override
	public int compareTo(Tuple that){
		return this.val - that.val;
	}
}

373. Find K Pairs with Smallest Sums

一、题目

Problem Description:
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k.
Define a pair (u,v) which consists of one element from the first array and one element from the second array.
Find the k pairs (u1,v1),(u2,v2) …(uk,vk) with the smallest sums.

Example 1:
Input: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
Output: [[1,2],[1,4],[1,6]]
Explanation: The first 3 pairs are returned from the sequence: [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

Example 2:
Input: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
Output: [1,1],[1,1]
Explanation: The first 2 pairs are returned from the sequence: [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

Example 3:
Input: nums1 = [1,2], nums2 = [3], k = 3
Output: [1,3],[2,3]
Explanation: All possible pairs are returned from the sequence: [1,3],[2,3]

二、题解

Approach #1 : Heap(PriorityQueue)
普通解题思路:
依次遍历两个数组的元素并求和矩阵各个元素,并将其插入至k个容量的最大优先队列。优先队列中始终留下的是k个元素值较小的元素。

//Heap(PriorityQueue)
//Time complexity : O(nmlogk);  Space complexity : O(k)
class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
		//lambda表达式定义比较器
		Queue<List<Integer>> queue = new PriorityQueue<>((num1, num2) -> (num2.get(0) + num2.get(1) - num1.get(0) - num1.get(1)));//倒序,最大优先队列
		for(int i = 0; i < nums1.length; i++){
			for(int j = 0; j < nums2.length; j++){
				//Define a pair [u,v] which consists of one element from the first array and one element from the second array.
				List<Integer> tempList = new ArrayList<>();
                tempList.add(nums1[i]);
                tempList.add(nums2[j]);
				//将[u,v]添加至queue
				queue.offer(tempList);
				//优先队列中最多留下K个u+v较小的[u,v],即queue.size()<=k
				if(queue.size() > k){
					queue.poll();//最大优先队列,大根堆,u+v最大的[u,v]出队
				}
			}
		}
        List<List<Integer>> resList = new ArrayList<>();
		//遍历优先队列,将[u,v]出队至resList
		while(queue.size() > 0){
			resList.add(queue.poll());
		}
		return resList;
    }
}

提交结果:
373提交结果1
注:
此解法这样书写更直观,更利于理解,但由于解题过程中没有用到"two integer arrays nums1 and nums2 sorted in ascending order"这个条件,运行时间较长,因此结合此条件,针对时间复杂度方面还可以做以下进一步优化。

优化解题思路:
可以将(nums1[i]+nums2[j])构建一个m*n的矩阵,即将373题"two integer arrays nums1 and nums2 sorted in ascending order"条件转换为378题"each of the rows and columns are sorted in ascending order"条件,则得到与378题相同思路的优化解法。
example:
373题例子
1.Build a minHeap of elements from the first row.
2.Do the following operations k-1 times :
Every time when you poll out the root(Top Element in Heap), you need to know the row number and column number of that element(so we can create a tuple class here), replace that root with the next element from the same column.

//Heap(PriorityQueue)
//Time complexity : O(klogk);  Space complexity : O(k)
class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
		//lambda表达式定义比较器
		Queue<Tuple> queue = new PriorityQueue<>();//顺序,最小优先队列
		int m = nums1.length;
		int n = nums2.length;
        List<List<Integer>> resList = new ArrayList<>();
        if(nums1 == null || m == 0 || nums2 == null || n == 0 || k <= 0) return resList;
		//1.Build a minHeap of elements from the first row.
		for(int i = 0; i < m; i++){
			queue.offer(new Tuple(0, i, nums1[i]+nums2[0]));
		}
		/*2.Do the following operations Math.min(k, m*n) times :
		Every time when you poll out the root(Top Element in Heap), 
		you need to know the row number and column number of that element(so we can create a tuple class here), 
		replace that root with the next element from the same column.
		*/
		for(int i = 0; i < Math.min(k, m*n); i++){
			Tuple t = queue.poll();
			List<Integer> tempList = new ArrayList<>();
			tempList.add(nums1[t.y]);
			tempList.add(nums2[t.x]);
			resList.add(tempList);
			if(t.x == n-1) continue;
			queue.offer(new Tuple(t.x+1, t.y, nums2[t.x+1]+nums1[t.y]));
		}
		return resList;
    }
}
class Tuple implements Comparable<Tuple>{
	int x, y, val;
	public Tuple(int x, int y, int val){
		this.x = x;
		this.y = y;
		this.val = val;
	}
	@Override
	public int compareTo(Tuple that){
		return this.val - that.val;
	}
}

优化后的提交结果:
373题提交结果2
从上图的提交结果来看,运行时间大大缩短,优化效果良好。
—— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— ——

未完待续…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值