Python要求O(n)复杂度求无序列表中第K的大元素实例


Posted in Python onApril 02, 2020

昨天面试上来就是一个算法,平时基本的算法还行,结果变个法就不会了。。。感觉应该刷一波Leecode冷静下。。。今天抽空看下。

题目就是要求O(n)复杂度求无序列表中第K的大元素

如果没有复杂度的限制很简单。。。加了O(n)复杂度确实有点蒙

虽然当时面试官说思路对了,但是还是没搞出来,最后面试官提示用快排的思想

主要还是设立一个flag,列表中小于flag的组成左列表,大于等于flag的组成右列表,主要是不需要在对两侧列表在进行排序了,只需要生成左右列表就行,所以可以实现复杂度O(n)。

举个例子说明下步骤,比如有列表test_list=[6,5,4,3,2,1],找出第3大的元素,就是4,

如果flag=4:

l_list=[3,2,1]

r_list=[6,5]

因为第3大的元素,r_list长度为2,自然flag就是第3大的元素了,return flag,len(r_list)==k-1,就是结束递归的基线条件。

如果flag=1:

l_list=[]

r_list=[6,5,4,3,2]

问题就变成了求r_list里面第K大的元素了

如果flag=6:

l_list=[5,4,3,2,1]

r_list=[]

相当于求l_list里第k-(len(test_list)-len(r_list)+1)大的元素了,这里就是相当于求l_list=[5,4,3,2,1]第2大的元素

通过这三种情况进行递归,最终返回flag就是目标元素

最差复杂度就是n+n-1+n-2+n-3+......+1=(1+n)n/2,就是O(n²)

当时我就会回答出了最差复杂度肯定是n²啊,面试小哥说平均复杂度,我说计算平均复杂度好像很复杂吧?感觉他也有点蒙,就说每次都是二分的情况的复杂度,

当时竟然回答了个logn*logn。。。最后还是被面试管提示的。。。太尴尬了。。。

实际上如果每次刚好二分,第一次取flag比较次数是n,第二次是n/2,依次下去是n/4,n/8.....n/2

就是n+n/2+n/4....

最最丢人的是计算这个结果还想了一会。。。看样该做点高中上数学了。。。

实际结果自然是n(1+1/2+1/4+1/8+....1/2ⁿ)=2n,复杂度自然就是O(n)了

最后实现代码如下:

#给定一个无序列表,求出第K大的元素,要求复杂度O(n)
def find_k(test_list,k):
 flag=test_list[0]
 test_list.pop(0)
 l_list=[i for i in test_list if i < flag]
 r_list=[i for i in test_list if i >= flag]
 
 #结果递归的基线条件
 if len(r_list)==k-1:
  return flag
 elif len(r_list)>k-1:
  return find_k(r_list,k)
 else:
  #因为test_list.pop(0)让test_list少了一个元素,所以下面需要+1
  gap=len(test_list)-len(l_list)+1
  k=k-gap
  return find_k(l_list,k)
 
if __name__ == '__main__':
 test_list = [5, 4, 3, 2, 1,10,20,100]
 res=find_k(test_list,1)
 print(res)

补充知识:从N个数选取k个数的组合--不降原则(DFS)

原理 :不降原则(看代码前先看一下原理吧)

举个例子:

比如说在6里面随便选5个数,那么选法都是什么呢?

瞎枚举?

12345
12346

前两个还不会弄混

然后很可能就乱了

少点数可能不会乱

但是多了就不好整了

比如说在100里随便选50个数。

1 2 3 4 5 6 7 8 9 10 11 12…

所以我们可以运用不降原则:

保证枚举的这些数是升序排列

其实真正的不降原则还可以平

比如 1 2 2 3 3 4…

但是这里要说的“不降原则”不能平哦!

对于这道题也不能平

否则就有重复数字了

拿6个里面选3个举例子

1 2 3
1 2 4
1 2 5
1 2 6

第一轮枚举完毕。

第二个数加一

1 3 ?

这个“?”应该是4,因为是升序排列

1 3 4
1 3 5
1 3 6

接着,就是这样

1 4 5
1 4 6
1 5 6

第一位是1枚举完毕

第一位是2呢?

2 3 4
2 3 5
2 3 6
2 4 5
2 4 6
2 5 6

就是这样的,枚举十分清晰,对吗?

以此类推…

3 4 5
3 4 6
3 5 6
4 5 6

然后就枚举不了了,结束。

所以说,这样就可以避免判重了。

代码

#include<iostream>
#include<cstring>

using namespace std;
int n,k; //全局变量:从n个数的集合中选取k个数
int a[25]; //存放n个数的集合数据
int vis[25];//在dfs中记录数据是否被访问过
int re[25];//存放被选取的数字


void dfs(int step,int start)//参数step代表选取第几个数字,参数start代表从集合的第几个开始选
{
 if(step==k)//如果选够了k个就输出
 {
  for(int i=0;i<k;i++)
  {
   cout<<re[i]<<" ";
  }
  cout<<endl;
 }
 for(int i=start;i<n;i++)//不降原则的核心步骤1:从第i+1个开始选取数字(避免重选)
 {
  if(vis[i]==1)
   continue;
  vis[i]=1;
  re[step]=a[i];
  dfs(step+1,i+1); //不降原则的核心步骤2:从第i+1个开始选取数字(避免重选)
  vis[i]=0;
 }
 return;
}

int main()
{

 while(cin>>n>>k)
 {
  memset(a,0,sizeof(a));
  memset(re,0,sizeof(re));
  memset(vis,0,sizeof(vis));
  for(int i=0;i<n;i++)
  {
   cin>>a[i];
  }
  dfs(0,0);
 }
 return 0;
}

运行结果

Python要求O(n)复杂度求无序列表中第K的大元素实例

变形——从N个数中选取k个数求和(举一反三)

代码

#include<iostream>
#include<cstring>

using namespace std;
int n,k; //全局变量:从n个数的集合中选取k个数
int a[25]; //存放n个数的集合数据
int vis[25];//在dfs中记录数据是否被访问过
int re[25];//存放被选取的数字


void dfs(int step,int sum,int start)//参数step代表选取第几个数字,参数sum代表从选取前step-1个数时的总数,参数start代表从集合的第几个开始选
{
 if(step==k)//如果选够了k个就输出
 {
  cout<<re[0];
  for(int i=1;i<k;i++)
  {
   cout<<'+'<<re[i];
  }
  cout<<'='<<sum<<endl;
 }
 for(int i=start;i<n;i++)//不降原则的核心步骤1:从第i+1个开始选取数字(避免重选)
 {
  if(vis[i]==1)
   continue;
  vis[i]=1;
  re[step]=a[i];
  dfs(step+1,sum+a[i],i+1); //不降原则的核心步骤2:从第i+1个开始选取数字(避免重选)
  vis[i]=0;
 }
 return;
}

int main()
{

 while(cin>>n>>k)
 {
  memset(a,0,sizeof(a));
  memset(re,0,sizeof(re));
  memset(vis,0,sizeof(vis));
  for(int i=0;i<n;i++)
  {
   cin>>a[i];
  }
  dfs(0,0,0);
 }
 return 0;
}

运行结果

Python要求O(n)复杂度求无序列表中第K的大元素实例

变形——从N个数中选取k个数求积(举一反三)

代码

#include<iostream>
#include<cstring>

using namespace std;
int n,k; //全局变量:从n个数的集合中选取k个数
int a[25]; //存放n个数的集合数据
int vis[25];//在dfs中记录数据是否被访问过
int re[25];//存放被选取的数字


void dfs(int step,int sum,int start)//参数step代表选取第几个数字,参数start代表从集合的第几个开始选
{
 if(step==k)//如果选够了k个就输出
 {
  cout<<re[0];
  for(int i=1;i<k;i++)
  {
   cout<<'*'<<re[i];
  }
  cout<<'='<<sum<<endl;
 }
 for(int i=start;i<n;i++)//不降原则的核心步骤1:从第i+1个开始选取数字(避免重选)
 {
  if(vis[i]==1)
   continue;
  vis[i]=1;
  re[step]=a[i];
  dfs(step+1,sum*a[i],i+1); //不降原则的核心步骤2:从第i+1个开始选取数字(避免重选)
  vis[i]=0;
 }
 return;
}

int main()
{

 while(cin>>n>>k)
 {
  memset(a,0,sizeof(a));
  memset(re,0,sizeof(re));
  memset(vis,0,sizeof(vis));
  for(int i=0;i<n;i++)
  {
   cin>>a[i];
  }
  dfs(0,1,0);
 }
 return 0;
}

运行结果

Python要求O(n)复杂度求无序列表中第K的大元素实例

以上这篇Python要求O(n)复杂度求无序列表中第K的大元素实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基础入门详解(文件输入/输出 内建类型 字典操作使用方法)
Dec 08 Python
Python中的exec、eval使用实例
Sep 23 Python
python中redis的安装和使用
Dec 04 Python
Python编程对列表中字典元素进行排序的方法详解
May 26 Python
Python使用openpyxl读写excel文件的方法
Jun 30 Python
Python实现随机漫步功能
Jul 09 Python
python 获得任意路径下的文件及其根目录的方法
Feb 16 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
Mar 01 Python
Python Selenium 设置元素等待的三种方式
Mar 18 Python
Python实现ElGamal加密算法的示例代码
Jun 19 Python
python UIAutomator2使用超详细教程
Feb 19 Python
Python使用Web框架Flask开发项目
Jun 01 Python
Pytorch 使用不同版本的cuda的方法步骤
Apr 02 #Python
pytorch 中的重要模块化接口nn.Module的使用
Apr 02 #Python
python递归函数求n的阶乘,优缺点及递归次数设置方式
Apr 02 #Python
PyTorch中的C++扩展实现
Apr 02 #Python
python实现将列表中各个值快速赋值给多个变量
Apr 02 #Python
Python运行提示缺少模块问题解决方案
Apr 02 #Python
Pycharm配置PyQt5环境的教程
Apr 02 #Python
You might like
Cakephp 执行主要流程
2010/03/24 PHP
Ubuntu中搭建Nginx、PHP环境最简单的方法
2015/03/05 PHP
PHP stream_context_create()函数的使用示例
2015/05/12 PHP
从JavaScript的函数重名看其初始化方式
2007/03/08 Javascript
javascript实现上传图片前的预览(TX的面试题)
2007/08/20 Javascript
html数组字符串拼接的最快方法
2009/09/16 Javascript
javascript中的onkeyup和onkeydown区别介绍
2013/04/28 Javascript
JavaScript Math.ceil() 函数使用介绍
2013/12/11 Javascript
浅谈Javascript 执行顺序
2013/12/18 Javascript
JavaScript日期时间格式化函数分享
2014/05/05 Javascript
通过jquery 获取URL参数并进行转码
2014/08/18 Javascript
原生JavaScript实现合并多个数组示例
2014/09/21 Javascript
JavaScript通过function定义对象并给对象添加toString()方法实例分析
2015/03/23 Javascript
javascript中caller和callee详解
2015/08/10 Javascript
js简单判断flash是否加载完成的方法
2016/06/21 Javascript
如何在JS中实现相互转换XML和JSON
2016/07/19 Javascript
Javascript 正则表达式校验数字的简单实例
2016/11/02 Javascript
webpack常用配置项配置文件介绍
2016/11/07 Javascript
js中async函数结合promise的小案例浅析
2019/04/14 Javascript
jquery实现掷骰子小游戏
2019/10/24 jQuery
vue 使用 vue-pdf 实现pdf在线预览的示例代码
2020/04/26 Javascript
Javascript中Math.max和Math.max.apply的区别和用法详解
2020/08/24 Javascript
[07:59]2014DOTA2叨叨刀塔 林熊猫称被邀请赛现场盛况震撼
2014/07/21 DOTA
python获取本机mac地址和ip地址的方法
2015/04/29 Python
基于python实现百度翻译功能
2019/05/09 Python
python实现图片压缩代码实例
2019/08/12 Python
PyTorch中topk函数的用法详解
2020/01/02 Python
python 批量将中文名转换为拼音
2021/02/07 Python
高级电工工作职责
2013/11/21 职场文书
婚礼证婚人证婚词
2014/01/08 职场文书
投资合作协议书
2014/04/17 职场文书
个人贷款收入证明
2014/10/26 职场文书
处级干部考察材料
2014/12/24 职场文书
幼儿园父亲节活动总结
2015/02/12 职场文书
python实现简单区块链结构
2021/04/25 Python
redis哨兵常用命令和监控示例详解
2021/05/27 Redis