每日一题算法:2020年7月2日 [有序矩阵中第K小的元素]kthSmallest

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;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值