算法刷题【10】最小的k个数

12 篇文章 0 订阅
7 篇文章 0 订阅

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

方法一:快排后返回数组
1.1直接使用Arrays.sort()方法对数组进行排序,再用Arrays.copyOf()方法返回数组arr中最小的k个值。

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
     Arrays.sort(arr);//先进行排序
     return Arrays.copyOf(arr,k);//再将最小的k个数返回
}

1.2手写快排

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
      quickSort(arr,0,arr.length-1);
      return Arrays.copyOf(arr,k);
    }
    public void quickSort(int[]arr,int low,int high){
      if(low>=high){//如果low>=high说明数组中只有一个数,直接返回
          return; 
      }
      int i=low,j=high;//设置哨兵low和high分别代表分治区域中的最小和最大的数
      while(i<j){//只要哨兵没有相遇就一直循环
          while(i<j && arr[j]>=arr[low]) j--;//如果右边的数大于基准数,就继续向左遍历下一个
          while(i<j && arr[i]<=arr[low]) i++;//如果左边的数小于基准数,就继续向右遍历下一个
          swap(arr,i,j);//交换i和j的数值。  
      }
      swap(arr,i,low);//最好把基准数值和low位置的数值交换。这样i就是基准数的下标。
      //分治
      quickSort(arr,low,i-1);//左递归
      quickSort(arr,i+1,high);//右递归
    }
    public void swap(int[]arr,int i,int j){//交换函数
        int t=arr[i];
        arr[i]=arr[j];
        arr[j]=t;
    }
}

方法二:基于快速排序的数组划分

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if(k>=arr.length)//如果k比数组长度还大,直接返回整个数组
        return arr;
        else 
        return quickSortk(arr,0,arr.length-1,k);
    }
    
    public int[] quickSortk(int[]arr,int low,int high,int k){
        int i=low,j=high;
        while(i<j){//还是要先进行快速排序
            while(i<j && arr[j]>=arr[low]) j--;
            while(i<j && arr[i]<=arr[low]) i++;
            swap(arr,i,j);
        }
        swap(arr,i,low);
        //每次快排之后要检查k是否和i相等了,如果相等,就可以直接确定从0到i为最小的k个数。
        if(i<k){
            quickSortk(arr,i+1,high,k);//如果i<k,说明还要向右递归去找那剩下的k-i个数
        }
       if(i>k){//如果i>k,说明k个数都在i的范围里面,需要向左递归找到i里面最小的k个数。
           quickSortk(arr,low,i-1,k);
       }
        return Arrays.copyOf(arr,k);//如果i==k,就可以返回这个数组中的k个数了,这里我觉得k和i都可以,但是用i提交却不行,为什么呢?先留在这个,请各位指点。
    }

    public void swap(int[] arr,int i,int j){
        int t=arr[i];
        arr[i]=arr[j];
        arr[j]=t;
    }
}

方法三:堆,利用java中的优先队列PriorityQueue

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
       if(k==0||arr.length==0){
         return new int[0];//如果k=0或者数组长度为0,就返回一个空数组,不能直接返回arr。why?
       }
       //优先队列PriorityQueue是二叉小顶堆数据结构实现的,默认是小丁堆,所以要改为大顶堆
       Queue<Integer> pq=new PriorityQueue<Integer>((v1,v2)->v2-v1);
       for(int num:arr){//遍历arr数组
           if(pq.size() < k){//?????????没懂
               pq.offer(num);//将num插入(offer)优先队列
           }
           else if(num<pq.peek()){//如果数值比堆顶元素小,就把堆顶元素移出,把改元素插入堆。
               pq.poll();
               pq.offer(num);
           }
       }
         int[] res=new int[pq.size()];
         int idx=0;
         for(int num:pq){
           res[idx++]=num;
         }
         return res;
   }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值