题目·

输入整数数组 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]

限制:

0 <= k <= arr.length <= 10000 0 <= arr[i] <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

库函数排序

Java

class Solution {public int[] getLeastNumbers(int[] arr, int k) {int[] vec = new int[k];Arrays.sort(arr);for (int i = 0; i < k; ++i) {vec[i] = arr[i];}return vec;}
}

C++

class Solution {
public:vector<int> getLeastNumbers(vector<int>& arr, int k) {vector<int> vec(k, 0);sort(arr.begin(), arr.end());for (int i = 0; i < k; ++i) {vec[i] = arr[i];}return vec;}
};

快速排序解法

什么是快排

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

  • (1) 首先设定一个分界值,通过该分界值将数组分成左右两部分。

  • (2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。

  • (3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

  • (4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

快排图解

首先设定一个分界值

以基准元素划分为左右两部分

递归处理左半部分和右半部分

递归图解

递归文字讲解

递归三步曲:

  • 确定递归的入参

  • 确定递归的终止条件

  • 确定递推工作并重新进去递归

确定递归的入参

public static void sort(int [] arr, int k, int i, int j)
  • k是基准元素下标

  • i 是左边界

  • j 是右边界

确定递归的终止条件

从上述中分析可知,递归的终止条件是i必须小于j。

if ( i >= j) return;

确定递推工作并重新进去递归

我们的递推工作主要是之前的以基准元素划分为左右两部分 每一次递归都需要这样进行去递推。根据前面的思路:

    // k是数组下标 i 是数组的左节点 j 是数组的右节点public static void sort(int [] arr, int k, int i, int j) {if ( i >= j) return;int low = i; // 保存此数组的左边界int high = j; // 保存此数组的右边界i = k + 1;// i指向了k i从下一个元素开始while( i < j) {while (i < j && arr[j] >= arr[k] ) {j--; // 右侧元素大于基准 }// 上述循环结束,说明此时j的元素小于基准while (i < j && arr[i] <= arr[k]) {i++;// 左侧元素小于基准 }// 上述循环结束,说明此时i的元素大于基准swap(arr, i, j);// 此时把i 和 j 交换 结果就是大于基准的都在右边小于基准的都在左边// 继续重复上述过程 直到i == j 循环结束 说明已经按基准分开}
}public static void swap(int [] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}

上述是一次递归的过程

上述处理完成的结果是这个样子的:

接下来是进入递归:

进入左半边数组递归处理:

递归函数就是调用自己:sort(int [] arr, int k, int i, int j)  // k是数组下标 i 是数组的左节点 j 是数组的右节点

我们需要确定左半边数组的sort函数的每个参数是什么:

  • arr还是arr

  • k是什么:low 和 high 是数组的左右边界,看图,我们来对号入座即可,新的基准是数组的左边界,也就是low

  • i是什么,也代表新数组的左边界,也还是low

  • j是什么:j代表左半边数组的右边界,看图知i-1即可 所以进入到左半边数组是:

sort(arr, low, low, i-1); // 处理基准元素左侧

同理确定如何递归处理数组的右半边:

sort(arr, i+1 , i + 1,high); // 处理基准元素右侧

合并一下:

package com.company;public class Main {public static void main(String[] args) {// write your code hereint [] arr  = {1 ,2 ,3 ,0, 1, 5, 4};sort(arr, 0 , 0 , arr.length - 1);for(int i = 0;i < arr.length;i++) {System.out.print(arr[i]);}}// k是数组下标 i 是数组的左节点 j 是数组的右节点public static void sort(int [] arr, int k, int i, int j) {if ( i >= j) return;int low = i;int high = j;i = k + 1;// i指向了k i从下一个元素开始while( i < j) {while (i < j && arr[j] >= arr[k] ) {j--; // 右侧元素大于基准}// 上述循环结束,说明此时j的元素小于基准while (i < j && arr[i] <= arr[k]) {i++;// 左侧元素小于基准}// 上述循环结束,说明此时i的元素大于基准swap(arr, i, j);// 此时把i 和 j 交换 结果就是大于基准的都在右边小于基准的都在左边// 继续重复上述过程 直到i == j 循环结束 说明已经按基准分开}swap(arr, i, k); // 交换基准数 和 i 的位置。sort(arr, low, low, i-1); // 处理基准元素左侧sort(arr, i+1 , i + 1,high); // 处理基准元素右侧}public static void swap(int [] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}

快排动画

我们的目的是寻找最小的 k 个数。假设经过一次 partition 操作,基准元素位于下标 m,也就是说,左侧的数组有 m 个元素,是原数组中最小的 m 个数。那么:

  • 若 k = m,我们就找到了最小的 k 个数,就是左侧的数组;

  • 若 k<m,则最小的 k 个数一定都在左侧数组中,我们只需要对左侧数组递归地 parition 即可;

  • 若 k>m,则左侧数组中的 m 个数都属于最小的 k 个数,我们只需要对右侧数组递归地 parition 即可;

  • 也就是说,不必每次只会递归左半边数组或者右半边数组,不会全部左半边和右半边都去递归。

  • 具体代码区别就是在递归那里加一个判断,

代码·

Java

class Solution {public int[] getLeastNumbers(int[] arr, int k) {if (k >= arr.length) return arr;int AnotherK = k;return quickSort(arr,  k, 0, arr.length - 1);}public int [] quickSort(int [] arr,int k ,int i, int j) {int low = i;int high = j;// 一次处理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, low, i);// 一次处理结束 需要进行判断当前i和k之间的关系if (i == k) {return Arrays.copyOf(arr, k);}if (i > k) {quickSort(arr, k,low,i-1);} else {quickSort(arr,k,i+1,high);}return Arrays.copyOf(arr, k);}public  void swap(int [] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
}

C++

class Solution {
public:vector<int> getLeastNumbers(vector<int>& arr, int k) {if (k >= arr.size()) return arr;return quickSort(arr, k, 0, arr.size() - 1);}
private:vector<int> quickSort(vector<int>& arr, int k, int l, int r) {int i = l, j = r;while (i < j) {while (i < j && arr[j] >= arr[l]) j--;while (i < j && arr[i] <= arr[l]) i++;swap(arr[i], arr[j]);}swap(arr[i], arr[l]);if (i > k) return quickSort(arr, k, l, i - 1);if (i < k) return quickSort(arr, k, i + 1, r);vector<int> res;res.assign(arr.begin(), arr.begin() + k);return res;}
};

JS


/**** @param {number[]} arr* @param {number} start* @param {number} end* @return {number}*/
function partition(arr, start, end) {const k = arr[start];let left = start + 1,right = end;while (1) {while (left <= end && arr[left] <= k) ++left;while (right >= start + 1 && arr[right] >= k) --right;if (left >= right) {break;}[arr[left], arr[right]] = [arr[right], arr[left]];++left;--right;}[arr[right], arr[start]] = [arr[start], arr[right]];return right;
}/*** @param {number[]} arr* @param {number} k* @return {number[]}*/
var getLeastNumbers = function(arr, k) {const length = arr.length;if (k >= length) return arr;let left = 0,right = length - 1;let index = partition(arr, left, right);while (index !== k) {if (index < k) {left = index + 1;index = partition(arr, left, right);} else if (index > k) {right = index - 1;index = partition(arr, left, right);}}return arr.slice(0, k);
};

Python

class Solution(object):def getLeastNumbers(self, arr, k):""":type arr: List[int]:type k: int:rtype: List[int]"""# 方法一:partition方法(基于快速排序)if k > len(arr) or k <= 0:return [] start = 0end = len(arr) - 1index = self.quickSort(arr, start, end)while index != k-1:print(index)if index > k-1:end = index - 1index = self.quickSort(arr, start, end)if index < k-1:start = index + 1index = self.quickSort(arr, start, end)return arr[:k]def quickSort(self, arr, start, end):low = starthigh = endtemp = arr[start]while low < high:while low < high and arr[high] >= temp:high -= 1arr[low] = arr[high]while low <high and arr[low] < temp:low += 1arr[high] = arr[low]arr[low] = tempreturn low

写题10分钟,写题解8小时,一道头条面试题,真心难。相关推荐

  1. 手冲1分钟正常吗_甩脂10分钟=慢跑1个小时?懒人减肥甩脂机靠谱吗?

    有朋友开玩笑说: 我要瘦成一道闪电, 闪瞎旁人的双眼! 谁知却胖成了一堵墙, 挡住了人们的视线! 不过, 有不少商家就瞄准了 减肥这个消费热点, 推出了各种各样的减肥产品, 比如:甩脂机. (图片来自 ...

  2. 人体可以为手表供电了!运动 10 分钟,供电半小时

    来源|雷锋网 文|付静 "该系统工作原理在于,通过运动摆臂和流汗产生能量,快速持续地为电子设备供电." 2021 年 3 月 12 日,IDC 发布<中国可穿戴设备市场季度跟 ...

  3. 腾讯宣布捐赠1亿元驰援河南;苹果回应iPhone 安全隐患;贝索斯完成10分钟太空之旅|极客头条...

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews ...

  4. 程序员用10分钟写了个旅游管家APP,女友用了直呼贴心

    「呐,你知道吗? 听说樱花飘落的速度是秒速五厘米哦.」 听到阿珍又念起这句经典台词,阿强,这个对自然界的花期不太敏感的程序员,也收到了"樱花开了"的讯号. 春天的樱花不能错过,赏樱 ...

  5. python老师 课时费_花10分钟写一个Python脚本,搞定了初中老师一下午的工作

    有个朋友是一个初中老师.嗯,教学行政两手抓的那种初中老师. 一天晚上突然微信问我,怎么把图片转成PDF.懵了一下,这个直接打印成PDF不就可以了? 遂告诉他,结果感觉两个人不是一个世界的: 好不容易教 ...

  6. 猿创征文|Python3,10分钟写了一个WIFI 万(破) 能 (解) 钥 (神) 匙 (器),YYDS。

    wifi万能钥匙 1.引言 2.代码实战 2.1 思路 2.2 模块安装 2.3 代码实战 2.3.1 生成密码本 2.3.2 破解实战 3.总结 1.引言 小鱼:小屌丝,你家WIFI密码是多少? 小 ...

  7. 给新手看的 Micronaut 入门教程,10 分钟写出一个 Micronaut 程序

    以下内容均选自 Micronaut 入门实战:基于 JVM 的微服务框架 . Micronaut是什么? Micronaut 是一个现代化的基于 JVM 的全栈框架,用于构建模块化且易于测试的微服务或 ...

  8. python 帮助教师_花10分钟写一个Python脚本,搞定了初中老师一下午的工作

    有个朋友是一个初中老师.嗯,教学行政两手抓的那种初中老师. 一天晚上突然微信问我,怎么把图片转成PDF.懵了一下,这个直接打印成PDF不就可以了? 遂告诉他,结果感觉两个人不是一个世界的: 好不容易教 ...

  9. 10分钟写一个markdown编辑器

    marked.js Marked是一个Markdown解析引擎. vue.js Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vu ...

  10. 6款办公软件,让你10分钟搞定3小时的工作!

    工作时间占据我们一大半的时间,如何一边轻松工作,还能拿到高薪?这6款高效办公工具绝对不能错过,不仅能让你工作效率连跳三级,还让领导刮目相看. 01.会议帮手 - 讯飞听见 有没有觉得,每次开会,领导在 ...

最新文章

  1. 如何打造一个搞垮团队的绩效考核?
  2. 智能车竞赛技术报告 | 节能信标组 - 洛阳理工学院 - Since 2021
  3. 【图解】一图了解《上海市推进新一代信息基础设施建设 助力提升城市能级和核心竞争力三年行动计划(2018-2020年)》...
  4. Java中的主类概念以及public static void main方法的分析
  5. php图片上传方案,php图片上传
  6. 获取客户端IP和MAC
  7. cas修改界面html,为REST API配置的CAS将v1 / ticket重定向到登录HTML
  8. android alertdialog view,Android AlertDialog 方法setView(view,0,0,0,0)开发自定义对话框
  9. 安装SQL server需要重启计算机,解决安装sql server 需要重启问题
  10. 【python】52周存钱法改进
  11. 微信小程序 Unexpected token in JSON at position 0 设置二维码,并且使用js中JSON.parse()函数将二维码返回的值转化为json格式
  12. G - Nightmare Ⅱ (双向BFS)
  13. 【计算机视觉】相机标定原理(像素点与三维坐标点的转换)
  14. 计算机的软件教学设计七年级,计算机软件系统教学设计
  15. 【面经】寒冬中的一年半前端跳槽
  16. 从前慢-Python
  17. python爬虫 知乎_python爬虫——知乎(关于python的精华回答)
  18. openlayers5之聚合分析图层Cluster
  19. Window Installer Clean Up好用的软件管理工具
  20. 【报告分享】2021中国锂电行业发展-德勤(附下载)

热门文章

  1. 电路板的信号完整性问题及原因
  2. 关于git的cherry-pick命令
  3. UOJ #357. 【JOI2017春季合宿】Sparklers
  4. CrystalReport runtime的下载地址
  5. 中小型软件项目开发一般流程建议
  6. [译] 第二天:AngularJS - 认识AngularJS
  7. 关于android中的ramdisk.img及uImage无法包含驱动模块(*.ko)的问题
  8. IAR使用技巧 之 快捷键批量更换指定字符(以及Keil的全局替换功能)
  9. Linux操作系统中修改hostname
  10. 站闻资讯项目开发个人总结