新秀系列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.程 ...
随机推荐
- Vijos P1881 闪烁的星星 (加强自己多一点。。)
假设每次查询不是整个长度,但[x, y]此时间间隔. . 闲来无事写的,感觉是正确的.这将成为合并范围. #include <cstdio> #include <cstring> ...
- 如何判断一个Http Message的结束——python源码解读
HTTP/1.1 默认的连接方式是长连接,不能通过简单的TCP连接关闭判断HttpMessage的结束. 以下是几种判断HttpMessage结束的方式: 1. HTTP协议约定status ...
- c++堆栈实现
A Stack is a data-structure that You can only add an element to the top of the Stack, andYou can onl ...
- HTML介绍JS
首先,该脚本的链接插入HTML代码: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvU2h1aVRpYW5OYWlMdW8=/font/5a6L5L2T/f ...
- [视频解说]0基础课程-运营商-Java它J2se
本节解说 运营商应用 Java 算被分成: 算术运算符 颂值运营商 逻辑运算符 位运算符 元运算符 这里录制了 视频解说这几大类运算符,并有练习题提供大家 面试题: 1. 最有效率的方式算出2乘以8等 ...
- 创建Material Design风格Android应用--自定义阴影和裁剪视图
之前已经写过通过应用主题和使用ListView, CardView,应用Material Design样式,同一时候都都能够通过support library向下兼容.今天要写的阴影和视图裁剪.无法向 ...
- Lua面向对象设计(转)
首先对于Lua语言,它没有打算被用来进行大型的程序设计,相反,Lua目标定于小型到中型的程序设计,通常是作为大型系统的一部分,所以它只提供了一套精简的元素,很多高级语言的概念都没有.这样Lua就成为了 ...
- HDU 1815, POJ 2749 Building roads(2-sat)
HDU 1815, POJ 2749 Building roads pid=1815" target="_blank" style="">题目链 ...
- 玩转Web之JavaScript(一)-----javaScript语法总结(一) 与鼠标操作有关的语法
click() 对象.click() 使对象被点击. event.clientX 返回最后一次点击鼠标 X 坐标值: event.clientY 返回最后一次点击鼠标 Y 坐标值: event ...
- C/C++数据对齐汇总
C/C++数据对齐汇总 这里用两句话总结数据对齐的原则: (1)对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才干获得最好的性能: (2)如果len为结构体中长度最长的变量,s ...