出题:输入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后序序列的更多相关文章

  1. 《剑指offer》第四十题(最小的k个数)

    // 面试题40:最小的k个数 // 题目:输入n个整数,找出其中最小的k个数.例如输入4.5.1.6.2.7.3.8 // 这8个数字,则最小的4个数字是1.2.3.4. #include < ...

  2. 算法题解:最小的K个数(海量数据Top K问题)

    [本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 题目 输入 n ...

  3. 剑指offer——python【第29题】最小的K个数

    题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 思路 先排序后取数,排序可以用冒泡,插入,选择,快排,二分法等等, ...

  4. 算法练习-寻找最小的k个数

    练习问题来源 https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/02.01.html 要求 输入n个整数, ...

  5. Python算法题(二)——国际象棋棋盘(排列组合问题,最小的K个数)

    题目一(输出国际象棋棋盘)  分析: 用i控制行,j来控制列,根据i+j的和的变化来控制输出黑方格,还是白方格.   主要代码: for i in range(8): for j in range(8 ...

  6. [算法]找到无序数组中最小的K个数

    题目: 给定一个无序的整型数组arr,找到其中最小的k个数. 方法一: 将数组排序,排序后的数组的前k个数就是最小的k个数. 时间复杂度:O(nlogn) 方法二: 时间复杂度:O(nlogk) 维护 ...

  7. 算法练习:寻找最小的k个数

    参考July的文章:http://blog.csdn.net/v_JULY_v/article/details/6370650 寻找最小的k个数题目描述:查找最小的k个元素题目:输入n个整数,输出其中 ...

  8. 窥探算法之美妙——寻找数组中最小的K个数&python中巧用最大堆

    原文发表在我的博客主页,转载请注明出处 前言 不论是小算法或者大系统,堆一直是某种场景下程序员比较亲睐的数据结构,而在python中,由于数据结构的极其灵活性,list,tuple, dict在很多情 ...

  9. 算法笔记_035:寻找最小的k个数(Java)

    目录 1 问题描述 2 解决方案 2.1 全部排序法 2.2 部分排序法 2.3 用堆代替数组法 2.4线性选择算法   1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 ...

随机推荐

  1. 07_传智播客iOS视频教程_#import指令

    mac切换中英文输入法默认是Ctrl+空格键. 预处理指令的执行时机是在编译之前.在编译之前执行预处理指令. #import指令是包含文件,将指定的文件的内容在预编译的时候拷贝到写指令的地方. #im ...

  2. Linux系统挂载NTFS文件系统(转载)

    转自:http://hermesbox.blogbus.com/logs/47386987.html 今天尝试并成功的将一块500G的移动硬盘挂载到了RHEL5的系统上,甚感欣慰.想到也许以后自己或其 ...

  3. ES6躬行记(24)——代理和反射

    代理和反射是ES6新增的两个特性,两者之间是协调合作的关系,它们的具体功能将在接下来的章节中分别讲解. 一.代理 ES6引入代理(Proxy)地目的是拦截对象的内置操作,注入自定义的逻辑,改变对象的默 ...

  4. 洛谷 P2754 星际转移问题【最大流】

    判无解的方法非常粗暴:快T了还是没有合法方案,就是无解. 然后枚举答案,对于每一天都建一套太空站,s连地球,t连月球,上一天的太空站连向这一天的太空站,流量均为inf.然后对于每个飞船,上一天的停靠站 ...

  5. bzoj1048(记忆化搜索)

    1048: [HAOI2007]分割矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1218  Solved: 890[Submit][Statu ...

  6. 洛谷P3261 [JLOI2015]城池攻占(左偏树)

    传送门 每一个城市代表的点开一个小根堆,把每一个骑士合并到它开始攻占的城池所代表的点上 然后开始dfs,每一次把子树里那些还活着的骑士合并上来 然后再考虑当前点的堆,一直pop直到骑士全死光或者剩下的 ...

  7. selenium3 + python - js 内嵌滚动处理

    一.js内嵌html <!DOCTYPE html><html lang="en"><head> <meta charset=" ...

  8. 标准行cp功能

    #include<stdio.h> int main(int argc,char *argv[]) { FILE *src_fp,*des_fp; ]={}; ) { printf(&qu ...

  9. A - Supercentral Point CodeForces - 165A

    One day Vasya painted a Cartesian coordinate system on a piece of paper and marked some set of point ...

  10. Linux的proc文件系统 分类: linux 2014-06-02 10:21 623人阅读 评论(0) 收藏

    proc为一个内核数据结构接口,用户空间和内核空间可以通过该接口通信, 与普通文件不同的是,这些虚拟文件的内容都是动态创建的. proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间. ...