笔试算法题(03):最小第K个数 & 判定BST后序序列
出题:输入N个整数,要求输出其中最小的K个数;
分析:
- 快速排序和最小堆都可以解决最小(大)K个数的问题(时间复杂度为O(NlogN));另外可以建立大小为K的最大堆,将前K个数不断插入最大堆,对于之后的N-K个数,依次与堆顶元素进行比较,如果新元素更小则删除当前堆顶元素,并更新最大堆;如果新元素大则跳过;
- 第一种实现:快速排序框架,插入排序处理小子文件,随机函数选取split点,双向扫描;
- 第二种实现:最小堆框架,基于fixUp的堆构建策略(数组整体更新,bottom up),通过删除前K个堆顶元素获取最小K个数;
- 第三种实现:最大堆框架,基于fixDown的堆构建策略(0起点插入式,top down),首先构建K个数的最大堆,然后新元素与堆顶元素进行比较,小于则替换现有堆顶元素,更新最大堆;
解题:
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <time.h> void ShowMinK(int *array, int k) {
printf("\nMin k: \n");
for(int m=; m<=k;m++) {
printf("%d, ",array[m]);
}
} void merge(int *array, int i, int split, int j) {
/**
* 此版本采用的是双向遍历,left和right指针同时从左右向中间遍历
* 其他还有单向遍历和三相遍历,此处不作解释
* */
/**
* 首先将split元素交换到j作为参考元素
* */
int temp=array[split];
array[split]=array[j];
array[j]=temp; int left=i; int right=j-; while(true) {
/**
* 两个指针同时相向遍历,当指针相遇(交错)或者满足与array[j]
* 的特定关系,则暂时停止。
* */
while(left<right && array[left]<=array[j]) {
left++;
}
while(right>left && array[right]>array[j]) {
right--;
} if(left>=right) break; temp=array[left];
array[left]=array[right];
array[right]=temp;
left++;
right--;
}
/**
* 将split元素从j位置交换回分界位置
* */
temp=array[left];
array[left]=array[j];
array[j]=temp;
} void InsertSort(int *array, int i, int j) {
/**
* 此版本仅使用最基本的插入排序思想,左边的序列都已经排好序
* 每一次循环都是讲array[m]插入左边序列
* 其他版本可以将找到最大值并放到最左边,这样可以省去每次
* 循环中对左边范围的检查
* */
int temp,k;
for(int m=i+;m<=j;m++) {
temp=array[m];
k=m-;
while(k>=i) {
if(array[k]>temp) {
/**
* 当array[k]大于temp,则将其向前复制
* */
array[k+]=array[k];
} else {
/**
* 当array[k]小于等于temp,则最终将m插入
* array[k+1],此次插入结束
* */
break;
}
k--;
}
/**
* 注意不同的跳出条件,是从break跳出的还是k>=i跳出的
* */
array[k+]=temp;
}
} void MinKQuickSort(int *array, int i, int j, int k) {
/**
* 当数组长度小于7的时候,直接的插入排序将会优于更小的子递归
* */ if(j-i+ < ) {
InsertSort(array, i, j);
ShowMinK(array, k);
return;
} /**
* 使用随机函数rand()选择split的策略,避免最坏情况
* time()或者getpid()可以作为srand函数的参数
* */
if(i>j) return;
if(i==j && i==k){
ShowMinK(array,k);
return;
}
srand((int)time());
int split=rand()%(j-i+) + i;
merge(array, i, split, j); if(split > k) {
/**
* 当前的split大于k,所以前k小的数应该在左边部分,k已经是相对i
* 的计数,所以需要减去i
* */
MinKQuickSort(array, i, split-, k);
} else if(split < k) {
/**
*
* 当前的split小于k,所以前k小 的数应该在右边部分,k是相对i的
* 计数,现在需要相对split+1,所以需要更改
* */
MinKQuickSort(array, split+, j, k);
} else if(split == k) {
ShowMinK(array, k);
}
}
/**
*
* */
void MinFixUp(int *array, int length, int i) {
int start=i;
int temp,father;
while(start> && array[start]<array[start/]) { temp=array[father];
array[father]=array[start];
array[start]=temp;
start/=;;
}
} void MinFixDown(int *array, int length, int i) {
int s;
int temp, father;
while(*i<=length) {
s=*i;
if(s+<=length && array[s] > array[s+]) {
s++;
}
if(array[i]<=array[s]) break; temp=array[i];
array[i]=array[s];
array[s]=temp;
i=s;
}
} /**
* 从最后一个拥有子节点的内部节点开始逆向遍历到根节点
* */
void BuildMinHeap(int *array, int length) { for(int i=length/;i>=;i=i-) {
MinFixDown(array, length, i);
}
} /**
* 从array[1]开始存储元素,从而简化代码
* 首先构建最小堆,然后删除堆顶元素,缩小堆大小
* 更新堆结构,重复K次
* */
void MinKMiniHeap(int *array, int length, int k) {
BuildMinHeap(array, length);
int capability=length;
for(int i=;i<=k;i++) {
printf("%d, ",array[]);
array[]=array[capability];
capability--;
MinFixDown(array, capability, );
}
} void MaxFixUp(int *array, int length, int i) {} void MaxFixDown(int *array, int length, int i) {} void BuildMaxHeap(int *array, int k) {} void MinKMaxHeap(int *array, int length, int k) {
BuildMaxHeap(array, k);
for(int i=k+;i<=length;i++) {
if(array[]>array[i]) {
array[]=array[i];
MaxFixDown(array, k, );
}
} int capability=k;
for(int i=;i<=k;i++) {
printf("%d, ",array[]);
array[]=array[capability];
capability--;
MaxFixDown(array, capability, );
} }
出题:输入一个整数数组,判断该数组是否给定二元查找树(Binary Search Tree)的部分后序(Post Order)遍历结果(给定二元查找树,判定整数数组是否在其中);
分析:使用int *position作为对比位置记录
解题:
struct Node {
int value;
Node *left;
Node *right;
};
/**
* Binary Search Tree可能不是满树,所以有右子树不一定就有左子树
* 仅当子树中完全找到整个序列才返回true,否则返回false,使用position
* 记录当前的比较位置
* */
bool PostOrderCompare(Node *cur, int *array, int length, int *position) {
bool isLeft=false, isRight=false;
if(cur->left != NULL) {
/**
* 左子树存在时候的后序遍历
* */
isLeft=PostOrderCompare(cur->left, array, length, position);
if(!isLeft && cur->right != NULL) {
isRight=PostOrderCompare(cur->right, array, length, position);
}
} else if(cur->right != NULL) {
/**
* 仅右子树存在时候的后序遍历
* */
isRight=PostOrderCompare(cur->right, array, length, position);
} if(isLeft || isRight) return true;
/**
* 左右子树都还没有满足条件,处理当前节点
* */
printf("\ncurrent node: %d\n", cur->value);
printf("\ncurrent position value: %d\n", array[*position]);
if(cur->value == array[*position]) {
if(*position + == length) return true;
else {
/**
* 仅当当前值匹配的时候position才更新, 否则直接返回
* */
*position = *position+;
}
}
return false;
}
笔试算法题(03):最小第K个数 & 判定BST后序序列的更多相关文章
- 《剑指offer》第四十题(最小的k个数)
// 面试题40:最小的k个数 // 题目:输入n个整数,找出其中最小的k个数.例如输入4.5.1.6.2.7.3.8 // 这8个数字,则最小的4个数字是1.2.3.4. #include < ...
- 算法题解:最小的K个数(海量数据Top K问题)
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 题目 输入 n ...
- 剑指offer——python【第29题】最小的K个数
题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 思路 先排序后取数,排序可以用冒泡,插入,选择,快排,二分法等等, ...
- 算法练习-寻找最小的k个数
练习问题来源 https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/02.01.html 要求 输入n个整数, ...
- Python算法题(二)——国际象棋棋盘(排列组合问题,最小的K个数)
题目一(输出国际象棋棋盘) 分析: 用i控制行,j来控制列,根据i+j的和的变化来控制输出黑方格,还是白方格. 主要代码: for i in range(8): for j in range(8 ...
- [算法]找到无序数组中最小的K个数
题目: 给定一个无序的整型数组arr,找到其中最小的k个数. 方法一: 将数组排序,排序后的数组的前k个数就是最小的k个数. 时间复杂度:O(nlogn) 方法二: 时间复杂度:O(nlogk) 维护 ...
- 算法练习:寻找最小的k个数
参考July的文章:http://blog.csdn.net/v_JULY_v/article/details/6370650 寻找最小的k个数题目描述:查找最小的k个元素题目:输入n个整数,输出其中 ...
- 窥探算法之美妙——寻找数组中最小的K个数&python中巧用最大堆
原文发表在我的博客主页,转载请注明出处 前言 不论是小算法或者大系统,堆一直是某种场景下程序员比较亲睐的数据结构,而在python中,由于数据结构的极其灵活性,list,tuple, dict在很多情 ...
- 算法笔记_035:寻找最小的k个数(Java)
目录 1 问题描述 2 解决方案 2.1 全部排序法 2.2 部分排序法 2.3 用堆代替数组法 2.4线性选择算法 1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 ...
随机推荐
- unity3d中对像之间的相互作用的实现
首先这里的对像是面向对像中的对像: 其实就是C#中对像间相互作用的实现: 一.一般面向对像中关联和依赖的方式: 如关联方式: class A{ B m_B; A(B b){ m_B = b; } ac ...
- svn报错:privious operation has not finshed;run 'cleanup' if it was interrupted
在更新svn的过程中,可能中途会取消,取消之后再次更新时可能提示,如下图: 下载sqlite3工具,进入此下载地址:https://www.sqlite.org/download.html 将sqli ...
- bzoj 4815: [Cqoi2017]小Q的表格【欧拉函数+分块】
参考:http://blog.csdn.net/qq_33229466/article/details/70174227 看这个等式的形式就像高精gcd嘛-所以随便算一下就发现每次修改(a,b)影响到 ...
- oracle数据库当前用户下所有表名和表名的注释
select a.TABLE_NAME,b.COMMENTSfrom user_tables a,user_tab_comments bWHERE a.TABLE_NAME=b.TABLE_NAMEo ...
- 递推DP UVA 607 Scheduling Lectures
题目传送门 题意:教授给学生上课,有n个主题,每个主题有ti时间,上课有两个限制:1. 每个主题只能在一节课内讲完,不能分开在多节课:2. 必须按主题顺序讲,不能打乱.一节课L时间,如果提前下课了,按 ...
- laravel5.5文件上传
/** * 上传文件 * @param Request $request * @return array */ public function upload(Re ...
- Caused by: javax.el.PropertyNotFoundException: Property 'product' not found on type java.lang.String
今天在JSP利用EL表达式取值报了 "javax.el.PropertyNotFoundException”,经过debug和打印将问题定位到这段代码: HTML应该是没啥问题,看提示在ja ...
- 公众号如何获取已关注用户的unionid的问题
避免误导,先加一句:首先,得公众号绑定开放平台 这个问题困扰了我一早上,我尝试了很多次获取unionid都失败. 微信的开发文档上有说: 关于特殊场景下的静默授权 1.上面已经提到,对于以snsapi ...
- 使用过Fetch之后,你还想使用AJAX吗
之前做数据交互的时候,请求数据一直使用ajax,看到网上有使用Fetch,所以也想拿来尝尝鲜 本次介绍只涉及fetch相关,传统的ajax基本上不涉及 当然你也要考虑兼容.浏览器支持情况. 一会这个只 ...
- IntentFilter的相关问题解析
IntentFilter是配合Intent而生的,你有目标行动或者结果,那么那些行动和结果就会有他完成的特定要求,这些要求就是IntentFilter,可以理解为Intent和IntentFilter ...