笔试算法题(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 ...
随机推荐
- (转)ASP.NET 4.0 尚未在 Web 服务器上注册
安装vs2010的时候忘记先安装IIS7了,导致出现了这个问题.经过网络查询发现解决方法如下: 运行:cmd命令,进入命令管理器, 输入:cd C:\\WINDOWS\\Microsoft.NET\\ ...
- CCF 201409-1 相邻数对 (水题)
问题描述 给定n个不同的整数,问这些数中有多少对整数,它们的值正好相差1. 输入格式 输入的第一行包含一个整数n,表示给定整数的个数. 第二行包含所给定的n个整数. 输出格式 输出一个整数,表示值正好 ...
- appium封装显示等待Wait类和ExpectedCondition接口
此文已由作者夏鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 使用WebDriver做Web自动化的时候,org.openqa.selenium.support.ui中提供 ...
- hdu1115【多边形求重心模板】
1.质量集中在顶点上.n个顶点坐标为(xi,yi),质量为mi,则重心(∑( xi×mi ) / ∑mi, ∑( yi×mi ) / ∑mi) 2.质量分布均匀.这个题就是这一类型,算法和上面的不同. ...
- [App Store Connect帮助]九、衡量 App 表现(1)分析和报告概述
App Store Connect 提供如下分析和报告,以衡量您 App 的表现并查看向您支付的最终付款. App 分析 通过 App Store 展示次数.产品页面查看次数.销售额.App 使用次数 ...
- 【POJ - 1661】Help Jimmy (动态规划)
Help Jimmy Descriptions: "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长 ...
- 团队作业-项目Alpha版本发布
一. 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2 这个作业要求在哪里 https://edu.cn ...
- TRACE Method 网站漏洞,你关闭了吗[转]
危险:该漏洞可能篡改网页HTML 源码 最近采用360 web scan 对服务器进行扫描.发现漏洞.TRACE Method Enabled 安全打分98分.前一阵有网页JS被人篡改,可能就是从这个 ...
- 进击的Python【第十四章】:Web前端基础之Javascript
进击的Python[第十四章]:Web前端基础之Javascript 一.javascript是什么 JavaScript 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编 ...
- 水题 Gym 100553K Knockout Racing
题目传送门 /* 题意:有若干个点在一个区间内来回移动,1m/s. 水题:n^2的复杂度能解决,注意时间可能大于一个周期,要取模 */ #include <cstdio> #include ...