一个主题:查找最小的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++经典问题(四)的更多相关文章

  1. 新秀系列C/C++经典问题(六)

    类包含一个指向成员复制 称号:下面是类和执行的阵列的声明.题.并针对存在的问题提出几种解决方式. template<typename T> class Array { public: Ar ...

  2. 计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践

    计算广告CTR预估系列(七)--Facebook经典模型LR+GBDT理论与实践 2018年06月13日 16:38:11 轻春 阅读数 6004更多 分类专栏: 机器学习 机器学习荐货情报局   版 ...

  3. Linux Shell系列教程之(十四) Shell Select教程

    本文是Linux Shell系列教程的第(十四)篇,更多Linux Shell教程请看:Linux Shell系列教程 在上一篇文章:Linux Shell系列教程之(十三)Shell分支语句case ...

  4. 【D3.V3.js系列教程】--(十四)有路径的文字

    [D3.V3.js系列教程]--(十四)有路径的文字 1. 在 svg 中插入一個 text // 在 body 中插入一個 svg var svg = d3.select('body').appen ...

  5. Django 系列博客(十四)

    Django 系列博客(十四) 前言 本篇博客介绍在 html 中使用 ajax 与后台进行数据交互. 什么是 ajax ajax(Asynchronous Javascript And XML)翻译 ...

  6. (转)Linux Shell系列教程之(十四) Shell Select教程

    本文属于<Linux Shell 系列教程>文章系列,该系列共包括以下 18 部分: Linux Shell系列教程之(一)Shell简介 Linux Shell系列教程之(二)第一个Sh ...

  7. 《手把手教你》系列技巧篇(十四)-java+ selenium自动化测试-元素定位大法之By xpath上卷(详细教程)

    1.简介 按宏哥计划,本文继续介绍WebDriver关于元素定位大法,这篇介绍定位倒数二个方法:By xpath.xpath 的定位方法, 非常强大.  使用这种方法几乎可以定位到页面上的任意元素. ...

  8. 寒武纪加速平台(MLU200系列) 摸鱼指南(四)--- 边缘端实例程序分析

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  9. Java经典算法四十例编程详解+程序实例

    JAVA经典算法40例 [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?   1.程 ...

随机推荐

  1. Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程

    原文:Red Gate系列之三 SQL Server 开发利器 SQL Prompt 5.3.4.1 Edition T-SQL智能感知分析器 完全破解+使用教程 Red Gate系列之三 SQL S ...

  2. MVC模型与FishiGUI应用层MVC型号

    MVC概要: MVC (Modal View Controler)M是指数据模型,V是指用户界面,C则是控制器. 使用MVC的目的是将M和V的实现代码分离,从而使同一个程序能够使用不同的表现形式.比方 ...

  3. 长方柱类【C++ 类定义】

    Description 编写基于对象的程序,求长方柱(Bulk)的体积.数据成员包括长(length).宽(width).高(heigth).体积,要求用成员函数实现下面的功能: (1)由键盘输入长方 ...

  4. 左右canvas.drawArc,canvas.drawOval 和RectF 关联

    1.paint.setStyle(Paint.Style.STROKE) // radius="100dp" // interRadius="40dp" // ...

  5. maven snapshot和release版本号之间的差

    在使用maven过程.我们经常会在不稳定的状态有很多公共图书馆在发展阶段.需要改变在任何时间和公布,你可能有一天一次发布.经验bug时间,甚至一天公布N次要.我们知道,.maven依赖管理是基于管理的 ...

  6. 让c#的exe只要被修改就无法运行,支持混淆和数字证书

    原文:让c#的exe只要被修改就无法运行,支持混淆和数字证书 首先用sdk的sn工具或者makecert工具生成公钥和密钥,推荐makecert,做自己的证书,我做了一个受信任的根证书放在受信任的根证 ...

  7. JDBC连接数据库 prepareStatement

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...

  8. MVC模式编程演示样本-登录认证(静态)

    好,部分博客分享我的总结JSP-Servlet-JavaBean思想认识和三层编程模型的基本流程,ZH- CNMVC该示例实现演示的编程模式-登录身份验证过程,在这里,我仍在使用静态验证usernam ...

  9. 【数据库摘要】4_Sql_Like

    SQL LIKE 操作符 LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. SQL LIKE 语法 SELECT column_name(s) FROM table_name WHERE ...

  10. HDU 5052 LCT

    Yaoge's maximum profit Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...