笔试算法题(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 ...
随机推荐
- JavaScript--DOM创建元素节点createElement
创建元素节点createElement createElement()方法可创建元素节点.此方法可返回一个 Element 对象. 语法: document.createElement(tagName ...
- Qt之程序发布以及打包成exe安装包
一.简述 Qt项目开发完成之后,需要打包发布程序,而因为用户电脑上没有Qt配置环境,所以需要将release生成的exe文件和所依赖的dll文件复制到一个文件夹中,然后再用 Inno Setup打包工 ...
- egrep命令的实现 分类: 编译原理 2014-06-01 23:41 329人阅读 评论(0) 收藏
本程序实现了egrep命令,首先将正则表达式转换为NFA,并实现模拟NFA的算法. 本程序使用flex实现词法分析,bison实现语法分析 若给定的一行字符串中存在一个字串能被该NFA接受,则输出整行 ...
- 转 ORA-12638: 身份证明检索失败
ORA-12638: 身份证明检索失败 的解决办法 2008年06月25日 星期三 11:42 the NTS option makes the Oracle client attempt to us ...
- 转 叫板OpenStack:用Docker实现私有云
http://www.cnblogs.com/alexkn/p/4239457.html 看到各大厂商的云主机,会不会觉得高大上?目前大公司的主流方案是OpenStack,比如某个公司的私有云
- ASP.NET网站发布到服务器
我们一个项目做好了之后想要上线,首先得发布,然后在上传到服务器. 所用到的工具:vs2013(其它vs版本也可以,大致上是一样的) FTP破解版下载链接:http://files.cnblogs.co ...
- AJPFX总结final、finally、finallize的区别
final.finally.finallize有何区别? final表示一个修饰符,如果用它来修饰一个类,则该类是不能继承的:如果用它来修饰一个变量,则该变量一旦赋值之后就不能再修改:如果用它来 ...
- LN : leetcode 646 Maximum Length of Pair Chain
lc 646 Maximum Length of Pair Chain 646 Maximum Length of Pair Chain You are given n pairs of number ...
- javascript实现弹层效果
首先,需要有一个按钮来模拟登录: <button id="btnLogin"class="login-btn">登录</button> ...
- K2 blackpearl 安装向导
最近我在Windows Server 2012 R2上面安装K2 blackpearl遇到了不小的麻烦,于是乎写了这篇向导,把自己遇到的问题记录下来,留给自己和需要帮助的人参考. 首先要解压缩blac ...