2020年7月2日 有序矩阵中第K小的元素 kthSmallest
默认格式:
class Solution {
public int kthSmallest(int[][] matrix, int k) {
}
}
解题思路:
维护一个数组记录每一行当前的位置。遍历这个数组,找到原数组中实际值的最小坐标,维护数组中的位置后移一位。
起始状态:
找一个最小值,地址+1
找下一个最小值,地址+1
找第三个最小值,地址+1
预计时间复杂度(K*N)空间复杂度(N)
这么做有一个问题,没有利用纵向也是有序的这一个特点
优化:
使用一个链表来存储这个坐标,链表头部的值比后面的值都要大。
取出表头的位置,横坐标+1,找到链表的对应位置插入。
再次重复上述步骤,取出队头。
这样子空间复杂度增加了,时间复杂度减少了。
实现部分:
哎,还是办法不够好,通过了但是效率低
public int kthSmallest(int[][] matrix, int k) {
LinkedList<int[]> list=new LinkedList<>();
//构建一个工具有序链表
for (int i=0;i<matrix.length;i++){
int[] array=new int[3];
array[0]=0;
array[1]=i;
array[2]=matrix[0][i];
list.add(array);
}
for(int i=0;i<k-1;i++){
int[] oldArray=list.getFirst();
list.removeFirst();
int[] newArray=new int[3];
newArray[0]=oldArray[0]+1;
//如果当前列已经搜索到末尾了
if (newArray[0]==matrix.length)
continue;
newArray[1]=oldArray[1];
newArray[2]=matrix[newArray[0]][newArray[1]];
int index=0;
for (int[] array:list){
if (array[2]>newArray[2]){
list.add(index,newArray);
break;
}
index++;
}
if (index==list.size())
list.add(newArray);
}
return list.get(0)[2];
}
解题思路2:
做到一半的时候我想起了前几天写的前第k项值,那个时候用的方法叫做堆排序,现在我们这个二维数组只需要简单的变式就能实现堆排序的效果。
我们将每一个一维数组视作一个小顶堆,然后我们可以将这些小顶堆的顶做一个堆排序,得到一个由小顶堆组成的小顶堆。
先将一维数组转变为小顶堆
由小顶堆的堆顶组成一个小小顶堆。
使用堆排序的方法先对数组堆进行排序,再对得到的小顶堆进行排序,得到新的堆顶来作为数组的代表
然后对外部数组堆进行排序
依次查询k次就能找到第k个元素。
然后回忆一下堆排序
首先构建一个小顶堆,这个我们不需要做,因为给的就是一个有序数组
然后是获取堆顶,并且用堆尾来代替堆顶,并且递归使用父节点和左右子节点比较找出最小值来代替父节点,具体可以查看前两天的查找最大的第k个元素。
代码部分:
今天时间来不及了,写了差不多意思,应该还存在一些小问题。先看看官方的解答
官方没有一样的解答方式,所以我也不清楚实际上的复杂多是多少,经过我的计算应该是O(klogn)
int n;
int[] lengths;
public int kthSmallest(int[][] matrix, int k) {
n=matrix.length;
lengths=new int[n];
for (int i=0;i<k;i++){
//首尾互换
moveArray(matrix[0],lengths[0]);
//长度缩短
lengths[0]++;
//将头部重新排
adjustHeap(matrix[0], 0,lengths[0] );
//将数组重排
adjustHeaps(matrix,0 ,0 );
}
return matrix[0][0];
}
//交换二级堆
public void moveArray(int[] array,int length){
int val=array[0];
array[0]=array[n-length-1];
array[n-length-1]=val;
}
public void adjustHeap(int[] array,int index,int length){
//由于原本就是小顶堆,所以下面的两个子节点
if (2*index+2<n-length-1){
//左节点比右节点大
if (array[2*index+1]>array[2*index+2]){
int val=array[2*index+2];
array[2*index+2]=array[index];
array[index]=val;
adjustHeap(array, 2*index+2,length);
}else {
int val=array[2*index+1];
array[2*index+1]=array[index];
array[index]=val;
adjustHeap(array, 2*index+1,length);
}
}
else if (2*index+1<n-length-1){
int val=array[2*index+1];
array[2*index+1]=array[index];
array[index]=val;
}
}
//交换的同时需要交换长度数组
public void adjustHeaps(int[][] arrays,int index,int length){
//由于原本就是小顶堆,所以下面的两个子节点
if (2*index+2<n-length-1){
//左节点比右节点大
if (arrays[2*index+1][0]>arrays[2*index+2][0]){
int[] array=arrays[2*index+2];
int val=lengths[2*index+2];
arrays[2*index+2]=arrays[index];
lengths[2*index+2]=lengths[index];
arrays[index]=array;
lengths[index]=val;
adjustHeaps(arrays, 2*index+2,length);
}else {
int[] array=arrays[2*index+1];
int val=lengths[2*index+1];
arrays[2*index+1]=arrays[index];
lengths[2*index+1]=lengths[index];
arrays[index]=array;
lengths[index]=val;
adjustHeaps(arrays, 2*index+1,length);
}
}
else if (2*index+1<n-length-1){
int[] array=arrays[2*index+1];
int val=lengths[2*index+1];
arrays[2*index+1]=arrays[index];
lengths[2*index+1]=lengths[index];
arrays[index]=array;
lengths[index]=val;
}
}