新秀系列C/C++经典问题(四)
一个主题:查找最小的k个元素
输入n个整数。输出当中最小的k个。
比如输入1。2,3,4,5,6。7和8这8个数字,则最小的4个数字为1,2,3和4。
分析:这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数就是最小的k个数。
仅仅是这样的思路的时间复杂度为O(nlogn)。
我们试着寻找更快的解决思路。
我们能够先创建一个大小为k的数据容器来存储最小的k个数字。接下来我们每次从输入的n个整数中读入一个数。假设容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中。假设容器中已有k个数字了,也就是容器已满。此时我们不能再插入新的数字而仅仅能替换已有的数字。我们找出这已有的k个数中最大值。然和拿这次待插入的整数和这个最大值进行比較。假设待插入的值比当前已有的最大值小,则用这个数替换替换当前已有的最大值;假设带插入的值比当前已有的最大值还要大。那么这个数不可能是最小的k个整数之中的一个,由于我们容器内已经有k个数字比它小了,于是我们能够抛弃这个整数。
因此当容器满了之后。我们要做三件事情:一是在k个整数中找到最大数。二是有可能在这个容器中删除最大数,三是可能要插入一个新的数字,并保证k个整数依旧是排序的。假设我们用一个二叉树来实现这个数据容器,那么我们能在O(logk)时间内实现这三步操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk)。
我们能够选择用不同的二叉树来实现这个数据容器。因为我们每次都须要找到k个整数中的最大数字。我们非常easy想到用最大堆。在最大堆中,根结点的值总是大于它的子树中随意结点的值。于是我们每次能够在O(1)得到已有的k个数字中的最大值。但须要O(logk)时间完毕删除以及插入操作。
我们自己从头实现一个最大堆须要一定的代码。我们还能够採用红黑树来实现我们的容器。红黑树通过把结点分为红、黑两种颜色并依据一些规则确保树是平衡的,从而保证在红黑树中查找、删除和插入操作都仅仅须要O(logk)。在STL中set和multiset都是基于红黑树实现的。
假设面试官不反对我们用STL中的数据容器。我们就直接拿过来用吧。以下是基于STL中的multiset的參考代码:
typedef multiset<int, greater<int> > IntHeap; ///////////////////////////////////////////////////////////////////////
// find k least numbers in a vector
///////////////////////////////////////////////////////////////////////
void FindKLeastNumbers(
const vector<int>& data, // a vector of data
IntHeap& leastNumbers, // k least numbers, output
unsigned int k)
{
leastNumbers.clear(); if (k == 0 || data.size() < k)
{
return;
} vector<int>::const_iterator iter = data.begin();
for (; iter != data.end(); ++iter)
{
// if less than k numbers was inserted into leastNumbers
if ((leastNumbers.size()) < k)
leastNumbers.insert(*iter); // leastNumbers contains k numbers and it's full now
else
{
// first number in leastNumbers is the greatest one
IntHeap::iterator iterFirst = leastNumbers.begin(); // if is less than the previous greatest number
if (*iter < *(leastNumbers.begin()))
{
// replace the previous greatest number
leastNumbers.erase(iterFirst);
leastNumbers.insert(*iter);
}
}
}
}
题目二:二元树中和为某一值的全部路径
输入一个整数和一棵二元树。
从树的根结点開始往下訪问一直到叶结点所经过的全部结点形成一条路径。打印出和与输入整数相等的全部路径。
比如输入整数22和例如以下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7。
二元树结点的数据结构定义为:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
分析:这是百度的一道笔试题,考查对树这样的基本数据结构以及递归函数的理解。
当訪问到某一结点时。把该结点加入到路径上。并累加当前结点的值。
假设当前结点为叶结点而且当前路径的和刚好等于输入的整数。则当前的路径符合要求,我们把它打印出来。假设当前结点不是叶结点。则继续訪问它的子结点。
当前结点訪问结束后。递归函数将自己主动回到父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是一个栈结构。由于路径要与递归调用状态一致,而递归调用本质就是一个压栈和出栈的过程。
參考代码:
///////////////////////////////////////////////////////////////////////
// Find paths whose sum equal to expected sum
///////////////////////////////////////////////////////////////////////
void FindPath(
BinaryTreeNode* pTreeNode, // a node of binary tree
int expectedSum, // the expected sum
std::vector<int>& path, // a path from root to current node
int& currentSum // the sum of path
)
{
if (!pTreeNode)
return; currentSum += pTreeNode->m_nValue;
path.push_back(pTreeNode->m_nValue); // if the node is a leaf, and the sum is same as pre-defined,
// the path is what we want. print the path
bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);
if (currentSum == expectedSum && isLeaf)
{
std::vector<int>::iterator iter = path.begin();
for (; iter != path.end(); ++iter)
std::cout << *iter << '\t';
std::cout << std::endl;
} // if the node is not a leaf, goto its children
if (pTreeNode->m_pLeft)
FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);
if (pTreeNode->m_pRight)
FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum); // when we finish visiting a node and return to its parent node,
// we should delete this node from the path and
// minus the node's value from the current sum
currentSum -= pTreeNode->m_nValue;
path.pop_back();
}
今天看到了两个冠军, 一定要指出一个错误, 共享注明出处, 谢谢!
新秀系列C/C++经典问题(四)的更多相关文章
- 新秀系列C/C++经典问题(六)
类包含一个指向成员复制 称号:下面是类和执行的阵列的声明.题.并针对存在的问题提出几种解决方式. template<typename T> class Array { public: Ar ...
- 计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践
计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践 2018年06月13日 16:38:11 轻春 阅读数 6004更多 分类专栏: 机器学习 机器学习荐货情报局 版 ...
- Linux Shell系列教程之(十四) Shell Select教程
本文是Linux Shell系列教程的第(十四)篇,更多Linux Shell教程请看:Linux Shell系列教程 在上一篇文章:Linux Shell系列教程之(十三)Shell分支语句case ...
- 【D3.V3.js系列教程】--(十四)有路径的文字
[D3.V3.js系列教程]--(十四)有路径的文字 1. 在 svg 中插入一個 text // 在 body 中插入一個 svg var svg = d3.select('body').appen ...
- Django 系列博客(十四)
Django 系列博客(十四) 前言 本篇博客介绍在 html 中使用 ajax 与后台进行数据交互. 什么是 ajax ajax(Asynchronous Javascript And XML)翻译 ...
- (转)Linux Shell系列教程之(十四) Shell Select教程
本文属于<Linux Shell 系列教程>文章系列,该系列共包括以下 18 部分: Linux Shell系列教程之(一)Shell简介 Linux Shell系列教程之(二)第一个Sh ...
- 《手把手教你》系列技巧篇(十四)-java+ selenium自动化测试-元素定位大法之By xpath上卷(详细教程)
1.简介 按宏哥计划,本文继续介绍WebDriver关于元素定位大法,这篇介绍定位倒数二个方法:By xpath.xpath 的定位方法, 非常强大. 使用这种方法几乎可以定位到页面上的任意元素. ...
- 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- Java经典算法四十例编程详解+程序实例
JAVA经典算法40例 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程 ...
随机推荐
- HTTP2.0协议
HTTP2.0协议 http2协议的草案已经出来了,阅读了一下网上的中文版,http2尽可能的兼容http1.1.改进了http1.1协议的不足. http1.0和http1.1的缺点: 1.http ...
- 【leetcode】LRU
import java.util.HashMap; import java.util.Map; public class LRUCache { private int capacity; privat ...
- Word,Excel,pdf,txt等文件上传并提取内容
近期项目需求:1.要用到各种文件上传,下载. 2.并对文件进行搜索. 3.仅仅要文件里包括有搜索的内容,所有显示出来. 今天正好有时间整理一下,方便以后阅读,及对须要用到的朋友提供微薄之力.首先在实现 ...
- QT 4.7.6 驱动 罗技C720摄像头
编译器: mingw32 gcc 4.8.1 mingw32 g++ 4.8.1 QT 版本: 4.8.6 OpenCV版本: 3.0.0 测试平台: win7 x64 --------------- ...
- android-sdk-windows下载版
Android SDK 4.0.3 开发和执行环境配置 近期又装了一次最新版本号的ADK环境 眼下最新版是Android SDK 4.0.3 本文的插图和文本尽管是Android2.2的 步骤都是一样 ...
- javascript从定义到执行 js引擎 闭包
javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境 栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链 ...
- XMPP得知--建立一个管理类
参考其他demo之后,设立一个管理类的发现看起来更舒服,理-- 但在建立与server连接其中.发现 Connect Error: { NSLocalizedDescription = &qu ...
- 在Apk应用程序内,查找某个Activity。
转载请注明出处:http://blog.csdn.net/droyon/article/details/39933677 Intent intent = new Intent(Intent.ACTIO ...
- crm创建基于fetch自己的自定义报告
在解决方案资源管理器,右键点击"报表"目录.然后点击"增加了新的报告". 打开"报表向导". 在"欢迎来到报表向导"前, ...
- Linux/UNIX数据文件和信息系统
数据文件和信息系统 密码文件 在存储/etc/passwd在.以下功能可以用来获得密码文件条目. #include <sys/types.h> #include <pwd.h> ...