Find the Kth number(找第K大数)


题目再现

题目内容:
给定N个排序好的序列,每个序列内有M个数字。因此我们总共有N*M个数字,编号为1~N*M。
将N*M个数字排序后输出第K个数字是多少。Hint : 直接将N*M个数字做排序会超过时间限制。
Hint : 每次花O(N)的时间找一个数字,一直找到第K个数字也会超过时间限制。
Hint : 使用一个大小为N的heap,记录每个序列目前最小的数字是多少,以及这是该序列的第几个数字。
Hint : 不要将N*M个数字都产生出来,会超过memory限制。输入格式:
只有一笔测资。第一行有三个数字N M K,意义如题目所述。接下来的N行,每行有2个数字a b,代表一个f(x) = ax+b。这一行的序列即为[f(1), f(2), … , f(M)]。你可以假设每一行的f(x)都会是一个递增函数,使得你的序列肯定是排序好的序列(由小到大)。数字范围:
0 < N <= 17000
0 < M <= 100000 <= a,b <= 100输出格式:
输出一行数字,第K个数字是多少。输入样例:
3 3 7
1 3
2 2
3 1输出样例:
7
时间限制:500ms内存限制:128000kb

问题解决

解法一

解决这种第K大的问题,想到的第一点就是用堆排序的方式,堆的大小为K,如果要找第K小的数,就建立最大堆;如果要找第K大的数,就要建立最小堆。所以我的解法一就是建立一个K大的最大堆,堆顶就是要求的第K小的数。

#include <stdio.h>int arrHeap[1000000];
int n = 0; // heap positionvoid swap(x, y){  int t;  t = arrHeap[x];  arrHeap[x] = arrHeap[y];  arrHeap[y] = t;  
}  void shiftDown(int x){  int t, flag = 0;  while(x * 2 <= n && flag == 0){  if(arrHeap[x * 2] > arrHeap[x]){  t = x * 2;  }else{  t = x;  }  if(x * 2 + 1 <= n){  if(arrHeap[x * 2 + 1] > arrHeap[t]){  t = x * 2 + 1;  }  }   if(t == x){  flag = 1;  }else{  swap(x, t);  x = t;  }  }  
} void creatHeap(){  int i;  for(i = n / 2; i >= 1; i--){  shiftDown(i);  }  
}  int main(){int N, M, K;int a, b, i, tmp; scanf("%d %d %d", &N, &M, &K);while(N --){scanf("%d %d", &a, &b);for(i = 1; i <= M; i ++){tmp = a * i + b;if(n <= K - 1){arrHeap[++ n] = tmp;if( n == K){creatHeap();}}else if(tmp < arrHeap[1]){arrHeap[1] = tmp;shiftDown(1);}}}printf("%d", arrHeap[1]);return 0;
}

算法是没问题的,对于测试样例也是正确的,但是题目有时间限制,而要计算的数值又很大,我的算法是O(MN),所以超时 没有通过。

解法二

其实,题目中说过一点,给出N个M长度的序列,而且每个序列都是按照升序的方式排列好的,所以为了降低时间复杂度,可以不用堆排序,而用优先队列的方式进行,然后出队K - 1个,那么第K个数就是队头了,那么怎么建立这个优先队列呢?应该怎样进行存储呢?其实这就是问题的关键,根据题意,我们只需要按列的方式进行入队即可轻松完成,时间复杂度是O(NlogN)。

#include <stdio.h>
#include <stdlib.h>//用于存储N * M 个结点类型 
struct Item{int value;int indexRow;int indexCol;
};//优先队列(没办法C语言里面没有C++那样的STL,只能自已去写这个) 
struct Queen{struct Item value;struct Queen *next;
}; struct Item qTop(struct Queen **head){return (*head)->value;
}void qPop(struct Queen **head){struct Queen *qTemp;if((*head) != NULL){qTemp = *head;(*head) = (*head)->next;free(qTemp);        }
}void qPush(struct Queen **head, struct Item x){struct Queen *newNode, *qHead, *curr;curr = qHead = *head;newNode = (struct Queen *)malloc(sizeof(struct Queen));newNode->value = x;if(qHead == NULL || qHead->value.value > newNode->value.value){newNode->next = qHead;qHead = newNode;}else{while(1){if(curr->next == NULL || curr->next->value.value > newNode->value.value){newNode->next = curr->next;curr->next = newNode;break;}else{curr = curr->next;}}}*head = qHead;
}int main(){struct Queen *qHead = NULL;int N, M, K; int i, j;struct Item tmpItem;scanf("%d %d %d", &N, &M, &K);  //给输入的a, b建表int arrAB[N][2];    for(i = 0; i < N; i ++){scanf("%d %d", &arrAB[i][0], &arrAB[i][1]);} //初始化队列for(i = 0; i < N; i ++){tmpItem.value = arrAB[i][0] + arrAB[i][1];tmpItem.indexRow = i;tmpItem.indexCol = 1;qPush(&qHead, tmpItem);}//执行 K-1 次出队,在这个过程中不断添加下一个结点 for(i = 0; i < K - 1; i ++){tmpItem = qTop(&qHead);qPop(&qHead);if(tmpItem.indexCol + 1 <= M){ //防止K值过大超出范围 (可不加) tmpItem.indexCol ++;tmpItem.value =  arrAB[tmpItem.indexRow][0] * tmpItem.indexCol + arrAB[tmpItem.indexRow][1];qPush(&qHead, tmpItem);}} //OK,第K小个数找到printf("%d", qTop(&qHead).value); return 0;
}

因为优先队列的操作是我个人写的,所以要比C++ STL中的优先队列效率要差一点,C++用户可以直接使用STL操作,C用户如果想自己实现也可参考我写的。

博客名称:王乐平博客
博客地址:http://blog.lepingde.com
CSDN博客地址:http://blog.csdn.net/lecepin


这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Species Tree(HashTable实现)

题目再现 题目内容&#xff1a; 给定一个物种演化图&#xff0c; 关系的表示方式如下&#xff1a; x y : 表示x为y的先祖。 一个物种只会有一个先祖&#xff0c; 一个先祖可以有很多个演化出来的物种&#xff0c; 请你找出每个问题询问物种的祖父物种(先祖的先祖)&#xff0c;…

Adjacent Node Sum(邻接表处理)

题目再现 题目内容&#xff1a; 给定一个节点有权重的图&#xff0c; 请你计算与一个节点相邻的所有节点的权重和。 节点编号为1~N。 每个节点的编号即为他的权重。输入格式: 只有一组测资。 第一行有三个数字&#xff0c;N、M、Q。 N表示这张图有多少节点&#xff0c; M表示这…

Maze(BFS处理)

题目再现 题目内容&#xff1a; 给你一个迷宫&#xff0c; S为起点&#xff0c;E为终点。 请你找出走出迷宫所需要花费的最短步数。 你只能往上下左右四个方向移动。输入格式: 第一行有一个数字T&#xff0c;代表有T组测资。 每组测资的第一行有两个数字R、C&#xff0c; 代表…

Lotto(DFS处理)

题目再现 题目内容&#xff1a; 给定N个数字&#xff0c;再从中选定M个数字出来。 将每一种组合内的数字由小到大排列之后&#xff0c; 将所有组合按照字典序排列&#xff0c; 请你找出第X组的第Y个数字。 给定的数字为1~N。 范例1 (N,M,X,Y) (5,2,8,2) 所有组合按顺序排列为…

2016第七届蓝桥杯省赛C/C++ B组试题解析整理

引言 今天是蓝桥杯省赛举办的日子&#xff0c;是一个很激动人心的时刻&#xff0c;也是我第一次参加蓝桥杯&#xff0c;从上午9点到下午1点&#xff0c;做题时间历经4个小时&#xff0c;想想就过瘾。 下面整理一下这次比赛的题目。 *注&#xff1a;此处为了省事儿&#xff…

Linux 小知识翻译 - 「邮件服务器」

这次聊聊「邮件服务器」。 邮件服务器上通常会运行2个服务端软件&#xff0c;「SMTP服务器」和「POP服务器或者IMAP服务器」。 这2个东西&#xff0c;也许使用邮件客户端的人立马就明白了。因为设置邮件客户端的时候&#xff0c;需要指定「发信服务器」和「收信服务器」。 这2个…

终极结束进程方法API

引言 最近在机房里上课的时候&#xff0c;学生的电脑上都安装了相应的学生端软件&#xff0c;而这些软件并没法正常关闭&#xff0c;用任务管理器也无法关闭&#xff0c;下面我说一下如何用Windows API对这类顽固程序进行终结。 福利方法 由于相关方面的规定&#xff0c;这里…

Android Fragments 详细使用

2019独角兽企业重金招聘Python工程师标准>>> Fragments 诞生初衷 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片、片段。其上的是为了解决不同屏幕分辩率的动态和灵活UI设计。大屏幕如平板小屏幕如手机&#xff0c;平板电脑的设计使得其有更多…

安卓UI适配限定符

引言 对于程序在不同尺寸的Android机器上运行&#xff0c;对UI的适用性造成了额外的开销&#xff0c;不过限定符的出现&#xff0c;很方便的解决了这个问题。通过创建限定符相关的文件夹来解决资源的加载。 限定符用处 限定符(mdpi,tvdpi,hdpi)可以帮助我们判断屏幕密度 限定…

docker install on centos 6.x

2019独角兽企业重金招聘Python工程师标准>>> 参考文档:http://docs.docker.com/installation/centos/ 安装epel源 wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo 安装docker服务端 yum install docker-io 启动docker /etc/init.…

安卓活动(Activity)和碎片(Fragment)的生命周期

引言 对于安卓中生命周期的过程以及相应的事件的了解是非常重要的。 活动&#xff08;Activity&#xff09;的生命周期 Activity 类中定义了七个事件回调方法&#xff0c;与Activity生命周期的每一个环节对应。 1. onCreate() 这个方法你已经看到过很多次了&#xff0c;每个…

又开始写博了

2019独角兽企业重金招聘Python工程师标准>>> 因为太多东西需要记录&#xff0c;所以重新开博。脚印一把 转载于:https://my.oschina.net/junfrank/blog/286348

Android 代码实现查看SQLite数据库中的表

前言 以前写PHP的时候&#xff0c;内置了print_r()和var_dump()两个函数用于打印输出任意类型的数据内部结构&#xff0c;现在做Android的开发&#xff0c;发现并没有这种类似的函数&#xff0c;对于数据库的查看很不方便&#xff0c;于是就写了一下查看数据库表的方法代码。 …

Android 代码执行Linux Shell小记

引言 Android系统是基于Linux内核运行的&#xff0c;而做为一名Linux粉&#xff0c;不在Android上面运行一下Linux Shell怎么行呢&#xff1f; 最近发现了一个很好的Android Shell工具代码&#xff0c;在这里分享一下。 Shell核心代码 import java.io.BufferedReader; impor…

【iHMI43 4.3寸液晶模块】demo例程(版本1.02)发布

技术论坛&#xff1a;http://www.eeschool.org 博客地址&#xff1a;http://xiaomagee.cnblogs.com 官方网店&#xff1a;http://i-board.taobao.com 银杏科技 GINGKO TECH. 保留权利&#xff0c;转载请注明出处 一、简介&#xff1a; 1、iHMI43 演示程序(版本号&#xff1a;1…

Android 数据存储之文件存储小记

前言 Android操作文件的方式和JAVA I/O操作是十分类似的&#xff0c;在这个我小谈一下。 Android写入文件 在Android中Context类提供了openFileOutput()方法&#xff0c;用于文件写入。默认存储路径为/data/data/<package name>/files/中。 openFileOutput原型&#x…

Android 数据存储之SharedPreferences存储小记

前言 Android的数据存储机制中还提供了SharedPreferences&#xff0c;SharedPreferences是这其中最容易理解的数据存储技术&#xff0c;采用键值对的方式进行存储&#xff0c;而且支持存储多中数据类型。 获取SharedPreferences对象 SharedPreferences文件存放在/data/data/&…

Jackson、JSON-lib、Gson性能对比

2019独角兽企业重金招聘Python工程师标准>>> 近日做一些性能优化工作&#xff0c;在挑选JSON类库时&#xff0c;发现除了一般常用的JSON-lib外&#xff0c;还有一款号称性能最快的JSON处理器Jackson&#xff0c;于是用上了刚学会的JMeter&#xff0c;对这两个类库进…

IP地址定位器

软件截图 软件说明 软件名称&#xff1a;IP地址定位器 软件版本&#xff1a; 1.0 软件说明&#xff1a;当我们想通过IP具体到街道甚至门牌号&#xff0c;该怎么办&#xff1f;&#xff1f;&#xff1f;特开发IP地址定位器&#xff0c;结合高精度IP定位&#xff0c;可以通过I…

[题解]RQNOJ PID85 三个袋子

链接&#xff1a;http://www.rqnoj.cn/problem/85 思路&#xff1a;一个排列问题&#xff0c;递推式很简单&#xff0c;f(n1)3*f(n)-1 &#xff0c;由此可以推出通项公式&#xff0c;f(n)0.5*3^(n-1)0.5 。 但是这个数太大了&#xff0c;我们需要求的是f(n) mod K 。那么就必须…