一、Problem
You are given an m * n matrix, mat, and an integer k, which has its rows sorted in non-decreasing order.
You are allowed to choose exactly 1 element from each row to form an array. Return the Kth smallest array sum among all possible arrays.
Input: mat = [[1,3,11],[2,4,6]], k = 5
Output: 7
Explanation: Choosing one element from each row, the first k smallest sum are:
[1,2], [1,4], [3,2], [3,4], [1,6]. Where the 5th sum is 7.
Input: mat = [[1,10,10],[1,4,5],[2,3,6]], k = 7
Output: 9
Explanation: Choosing one element from each row, the first k smallest sum are:
[1,1,2], [1,1,3], [1,4,2], [1,4,3], [1,1,6], [1,5,2], [1,5,3]. Where the 7th sum is 9.
提示:
- m == mat.length
n == mat.length[i]
1 <= m, n <= 40
1 <= k <= min(200, n ^ m)
1 <= mat[i][j] <= 5000
mat[i] 是一個非遞減數組
方法一:暴力
估計一下運算量:m × n 最大爲 1600,k 最小爲 200,我們每次只保留前 k 個元素,也就是 200 × 1600,加上一些排序,集合的複製,絕對不會超時,而且會很快…
講大致的思路吧:
- 遍歷 mat 的每一行,將每一行和上一行沒有被篩出來的 k 個組合都組合一下。
- 每次組合完,再排序,排完在選前 k 個。
- 然後再遍歷 mat 的下一行。
public int kthSmallest(int[][] mat, int k) {
List<Integer> kl = new ArrayList<>();
for (int[] a : mat) {
List<Integer> t = new ArrayList<>();
for (int n1 : a) {
if (kl.size() == 0)
t.add(n1);
else for (int n2 : kl)
t.add(n1+n2);
}
Collections.sort(t);
if (t.size() > k)
t = t.subList(0, k);
kl = new ArrayList<>(t);
}
return kl.get(kl.size()-1);
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
參考方法二:bfs
別人的思路,不太懂 hhh…😂
class Solution {
public int kthSmallest(int[][] mat, int k) {
int m = mat.length;
int n = mat[0].length;
int initSum = 0;
for(int i=0; i<m; i++) {
initSum += mat[i][0];
}
if(k == 1) return initSum;
//pre process,mat保存增值
for(int i=0; i<m; i++) {
for(int j=n-1; j>0; j--) {
mat[i][j] -= mat[i][j-1];
}
}
Set<String> visited = new HashSet<>();
int[] list = new int[m]; //初始都是0
Node init = new Node(initSum, list);
PriorityQueue<Node> queue = new PriorityQueue<>((n1,n2)->n1.sum-n2.sum);
queue.add(init);
visited.add(init.code);
int cnt = 0;
while(!queue.isEmpty()) {
Node node = queue.poll();
cnt++;
if(cnt == k) {
return node.sum;
}
int[] pre = node.ins;
//遍歷所有的下一個位置
for(int i=0; i<m; i++) {
//當前行已經到最後一列了,不能繼續前進
if(pre[i]== n-1) continue;
int[] tmp = Arrays.copyOf(pre, m);
tmp[i]++;
//計算下一次的和,只需要添加增值
int cur = node.sum + mat[i][tmp[i]];
Node next = new Node(cur, tmp);
//是否已經計算過
if(visited.contains(next.code)) {
continue;
}
visited.add(next.code);
queue.add(new Node(cur, tmp));
}
}
return 0;
}
class Node {
int sum;
int[] ins; //indexList
String code; //去重code
public Node(){}
public Node(int sum, int[] ins){
this.sum = sum;
this.ins = ins;
StringBuilder sb = new StringBuilder();
for(int index : ins) {
sb.append(index).append(",");
}
this.code = sb.toString();
}
}
}