重建二叉树 POJ 2255
摘要:数据结构中的经典问题之一就是根据二叉树的某种遍历序列重建二叉树,比如给出前序和中序序列,但是要求输出后序遍历的结果。这里仅仅帖一份根据前序和中序遍历重建二叉树的代码吧(要输出后序遍历的结果,只要添加一个后序遍历函数即可),正好是POJ 2255的答案。#include <iostream>#include <map>#include <utility>#include <functional>#include <string>#include <stack>using namespace std;typedef char
阅读全文
posted @
2011-05-12 01:29
微型葡萄
阅读(668)
推荐(0)
[动态规划]最大连续子数组和的四种算法
摘要:思路来自于微软的《编程之美》。注意:子序列(subsequence)和连续子数组还是不一样的,子序列可以是不连续的。/*****************************列出了四种算法,复杂度从O(N^3)到O(N)Author: MicroGrapeDate:2009-5-20*****************************/#include <iostream>using namespace std;/*O(N^3) algorithm*/int MaxSubSumA(int a[], int n){int maxsum = 0;for(int i = 0; i
阅读全文
posted @
2011-05-12 01:24
微型葡萄
阅读(564)
推荐(0)
[贪心]Dijkstra最短路径算法
摘要:其实这个算法写了很多次了,但是总是理解不深。这次专门拿出时间好好的分析一下。【基本原理】称为三角算法。以下面的简单图示表示。假设v1是我们的源点,它的最短路径长度已固定(为0)。那么首先找到的最短路径是v1-v2。找到v2之后,我们最短路径长度已固定的节点的集合就变成了{v1,v2}。那么需要更新与v2邻接的所有节点的最短路径长度的值,由于1+2<5,所以v3的最短路径长度就更新为3而不是保持为5。当然,如果v2到v3的距离大于4,v3的最短路径长度是不需要更新的。Dijkstra的最短路径算法往往有几种存储方式,例如:(1)邻接矩阵。形如a[i][j]来存储节点i与节点j之间的路径。(
阅读全文
posted @
2011-05-12 01:24
微型葡萄
阅读(524)
推荐(0)
[迭代优化]Bellman-Ford最短路径算法
摘要:【原理】这个算法也是求最短路径时常用的算法,但由于其复杂度为O(EV)其中E、V分别为边的总数和顶点的总数。如果当为稠密图时,E也是O(V^2)的级别,因此整体复杂度会达到O(E^3)。如果是稀疏图,则无法达到使用优先队列的Dijkstra算法的O(E*logV)。因此,Bellman-Ford算法更适合于稠密图。但是它相比Dijkstra算法更好的一点就是,它能够处理带有负权值的边。但是依然无法处理负权值的回路,如果遇到的话会检测到,从而退出程序。算法思想如下:Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。对于给定的带权(有向或无向)图 G=(V,E),
阅读全文
posted @
2011-05-12 01:23
微型葡萄
阅读(615)
推荐(0)
[时空权衡]字符串匹配算法 KMP
摘要:字符串匹配是算法中的一个重要领域,常用在计算机科学的自然语言处理和模式匹配中。(一)经典的字符串匹配算法(1)穷举或者暴力法/brute force简称BF。(2)大名鼎鼎的KMP算法(Knuth-Morris-Pratt)。(3)Horspool算法及Boyer-Moore算法。(4)其他:如Sunday算法,BOM算法(Backward Oracle Matching),BNDM算法(Backward Nondeterministic Dawg Matching)等等。这些我根本就没有看过,本文中就不再讨论了。(二)字符串匹配算法的联系和区别我们要进行字符串匹配,肯定是一个字符一个字符的比
阅读全文
posted @
2011-05-12 01:21
微型葡萄
阅读(1035)
推荐(0)
[时空权衡]字符串匹配KMP算法代码(引自算法导论)
摘要:这里只贴一份来自《算法导论》的伪代码改写的代码。void KMP_prefix( const char *t, int *next ){int len = strlen(t) ;int i, j = -1 ; next[0] = -1 ;//请读者自行思考i什么时候增长for( i=1; i<len; ++i ) {//i永远和j+1位的比较(因为j初始值为-1)//如果失配就执行跳转。直到j为-1为止。while( (j+1>0)&&(t[j+1]!=t[i]) ) j = next[j] ;//如果匹配,则两个串的指针都增长if( t[j+1]==t[i] )+
阅读全文
posted @
2011-05-12 01:20
微型葡萄
阅读(394)
推荐(0)
[动态规划]背包问题(找零/子集和/编辑距离)
摘要:大名鼎鼎的“背包问题”我不敢企及去探讨,最近初学,感觉背包及相关问题真乃博大精深,于是把自己初学的体会写下来,帮助那些跟我一样也许暂时还没有思路的人。本文的核心算法都是动态规划。【问题】与背包问题近似的经典动态规划题目有(附相应的wiki条目):背包问题(knapsack problem)http://en.wikipedia.org/wiki/Knapsack_problem找零问题(coin changing/change making)http://en.wikipedia.org/wiki/Change-making_problem子集和问题(subset sum)http://en.
阅读全文
posted @
2011-05-12 01:18
微型葡萄
阅读(1396)
推荐(0)
[动态规划]矩阵连乘
摘要:矩阵连乘也是经典的动态规划的例子,而且能比较明显的把原来子问题的复杂度从指数级降为O(n^3),算是效果明显。【分析】算法的分析请见参考资料,我就不重复写了。就是写代码的时候需要注意两点:(1)这个程序是自底向上的动态规划。因为我们在一个段[ i : j ]中进行划分的时候,那么必须下面的每一个小段必须已经生成了。如下图所示:所以不能采用传统的那种i和j从头到尾的遍历(这种双重循环一般只适合于从前向后生成,比如最长公共子序列等动态规划)。(2)一开始对书中的递推式m[i][j] = m[i][k] + m[k][j] + pi-1 * pk * pj中的后面三项很不理解。为什么会是三项呢?书中
阅读全文
posted @
2011-05-12 01:17
微型葡萄
阅读(330)
推荐(0)
随机抽样/蓄水库抽样
摘要:【问题】随机抽样问题表示如下:要求从N个元素中随机的抽取k个元素,其中N无法确定。这种应用的场景一般是数据流的情况下,由于数据只能被读取一次,而且数据量很大,并不能全部保存,因此数据量N是无法在抽样开始时确定的;但又要保持随机性,于是有了这个问题。所以搜索网站有时候会问这样的问题。这里的核心问题就是“随机”,怎么才能是随机的抽取元素呢?我们设想,买彩票的时候,由于所有彩票的中奖概率都是一样的,所以我们才是“随机的”买彩票。那么要使抽取数据也随机,必须使每一个数据被抽样出来的概率都一样。【解决】解决方案就是蓄水库抽样(reservoid sampling)。主要思想就是保持一个集合(这个集合中的
阅读全文
posted @
2011-05-12 01:07
微型葡萄
阅读(359)
推荐(0)
栈的常见递归用法
摘要:下面是两道常见笔试题:栈的原地排序。(注:所谓原地就是指不需要额外的辅助空间,或者只需要常数个额外空间)栈的原地倒转。但是在这里递归的思想非常抽象,但是又不得不让人叹服!(我也是看了别人的答案,简直太经典了!)另外,虽然不允许另外使用额外空间,但实际上递归本身就要很多空间。。。【栈的原地倒转】这里的递归思想用语言描述太复杂,但是您一看代码,加上那一点注释,很快就能明白的。相信你也会为这个递归的用法感到奇妙!#include <iostream>#include <stack>using namespace std;//display the stackvoid prin
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(356)
推荐(0)
遍历序列唯一确定二叉树的问题
摘要:数据结构的基础知识中重要的一点就是能否根据两种不同遍历序列的组合(有三种:前序+中序,前序+后序,中序+后序),唯一的确定一棵二叉树。然后就是根据二叉树的不同遍历序列(前序、中序、后序),重构二叉树。下面是这个问题的证明与结论:①给定二叉树结点的前序序列和对称序(中序)序列,可以唯一确定该二叉树。证明:因为前序序列的第一个元素是根结点,该元素将二叉树中序序列分成两部分,左边(设1个元素)表示左子树,若左边无元素,则说明左子树为空;右边(设r个元素)是右子树,若为空,则右子树为空。根据前序遍历中"根-左子树-右子树"的顺序,则由从第二元素开始的1个结点序列和中序序列根左边的1
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(4855)
推荐(1)
区间覆盖问题
摘要:【问题】区间覆盖问题(Interval Cover Problem)常常又叫区间重合问题。一般情况下是求最少区间覆盖,顾名思义,就是用最少数量的小区间去覆盖一个更大的区间。但是本文所说的问题仅仅指的是:判断一个源区间能否被若干给定的已知区间覆盖,是个判断题。【例题】《编程之美》P211的“区间重合判断”就是一种区间覆盖问题。题目:给定源区间[1,6]和一组无序的目标区间[2,3][1,2][3,9],即可认为区间[1,6]在区间[2,3][1,2][3,9]内。【分析】参见编程之美。主要分以下三步:(1)排序。(2)合并。(3)搜索。(1和3具体请看编程之美书中的介绍)下面我只是讲解我的对“合
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(1533)
推荐(0)
子集与子集和问题(Subset sum)的递归回溯解
摘要:所谓子集,是一个数学中的概念。例如一个集合S = {1,2,3,4,5},那么X = {1,3,5}就是它的一个子集,1+3+5等于9就是对应于X的一个子集和。其实子集对于一个数组来说,就是相当于一个子序列(不是子数组,因为子序列意味着可以不连续,而子数组往往是连续的);那么子集和也就是子序列和。另外,子集问题需要与数学中的“排列”问题区分开来。因为子集往往是无序的,但排列是需要考虑顺序的;所以子集问题常常只是一个“组合”问题,而不是“排列”问题。从另一个角度讲,这种子集和问题是一种背包问题的特例。【问题1】下面举一个退化(之所以说退化,因为这里的子集的大小是2,比较特殊)的子集和问题的例子,
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(7932)
推荐(3)
彩票收集问题(Coupon Collector's Problem)
摘要:【问题】现在有一种彩票,总的有N个选择(比如36选7,那么总的选择就是36种),请问期望用多少次可以取到所有的彩票(有放回--当然,没放回就简单了。。。)?同样的一个题目就是:一个袋子里放N个不同的球,有放回的取球。请问期望用多少次可以取到所有不同的球?【解答】粗略的答案,这个期望次数是随着N的规模成O(N*logN)的规模扩大的。下面是分析:我们采取递推的方式,假设现在已经取到了i-1个不同的球或者不同的彩票(我们下边都用球代替),那么下一次取到第i个球的概率是:( N - ( i - 1 ) ) / N这个很显然:下次想取到一个跟以前的球不同的球,显然是在剩下的N-(i-1)个球中任取一个
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(5674)
推荐(0)
[笔试题]判断栈的增长方向
摘要:【方法一】函数参数与局部变量。函数参数先入栈,然后才是局部变量。如下面的代码,1-向上生长;0-向下生长。int stackDir( int x ) { int a; return (&a - &x)>0; }注意:不推荐同时使用两个局部变量的地址进行判断,因为有的时候编译器会做优化。【方法二】声明在两个不同函数作用域中的局部变量。如下面的代码:#include <iostream>#include <string>#include <algorithm>using namespace std;void func(){int temp;
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(286)
推荐(0)
[贪心]活动选择问题 Activity Selection的思想
摘要:【问题】活动选择问题的大致意思就是在一种只能被独占的资源上,现在有很多事务(这些事务只有两个参数:开始时间和结束时间)在竞争使用这个资源,如何能让更多数目的事务使用这个资源。计算机科学中的例子:比如这个资源是CPU,那么好多进程要竞争使用CPU,那么如何能让CPU处理更多的进程。现实生活中的例子:某大学里只有一间活动教室,用于举办各种学生活动。现在有学生会的各个部门来申请这间教室,如何分配这个教室,能使得这个活动教室举办活动更多呢?当然,我们仅仅考虑活动的开始和结束时间,而不考虑活动的优先级之类的。【参考文献】http://blog.csdn.net/a9529lty/archive/2009
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(865)
推荐(0)
翻硬币问题的一种玩法
摘要:【问题】原文参见这里:http://yueweitang.org/blog/posts/rotate-coin-games.html原文中只给出了一个结果,但是没有分析过程。最后我逆向了一下,有点拾人牙慧。我再引用一下人家的题目:Alice和Bob两人玩一种硬币游戏。游戏在一个的棋盘上进行,棋盘上每个格子上都有一枚硬币。在每一回合,Alice可以决定选择翻转某两枚或者一枚硬币,接着Bob可以选择将棋盘旋转90,180或者270度,也可以什么都不做。 游戏轮流进行直到棋盘上所有硬币都正面朝上或者反面朝上,Alice获得胜利。 如果Alice在游戏过程中无法看到棋盘上的银币,也不知道游戏刚开始的状
阅读全文
posted @
2011-05-11 22:57
微型葡萄
阅读(1440)
推荐(0)
[笔试题]网易有道:字符串表达式求值
摘要:下面是原题:表达式求值,一个字符串只由'+','-',和‘0’-‘9’组成,并且'+','-'只作为二元运算符。bool calculate(const char* exp, int &result);想了想,这个用STL做很简单,因为只有+号和-号,没有其他符号,只要从左向右即可,不需要用栈。存操作数的用双端队列,存操作符的用普通队列先进先出即可。下面是我的解决代码:#include <iostream>#include <string>#include <deque>#include
阅读全文
posted @
2011-05-11 22:56
微型葡萄
阅读(378)
推荐(0)
[分治]快速选择算法 C++实现
摘要:都有“快速”两个字,实际上快速选择算法跟快速排序算法的思想完全一样:先分区。也就是分治的思想。快速选择算法的目的就是找到数组中的第K大的数。我写的快速排序的算法见这里:http://hi.baidu.com/microgrape/blog/item/30b7f88a0166bd1bc9fc7a43.html可以对比一下下面的快速选择算法的代码。#include <iostream>#include <vector>using namespace std;//search the kth biggest numberint QuickSelect(vector<in
阅读全文
posted @
2011-05-11 22:56
微型葡萄
阅读(1996)
推荐(2)
二叉树的遍历(C++非递归实现)
摘要:其实二叉树的遍历,这么经典的东西,我自己一直都不明白。递归算法那么简洁,让人神魂颠倒;非递归算法就那么不好理解。。。最近使劲想了一想,似乎有一些眉目了,于是记录下来。【思想】(1)递归思想。虽然非递归算法没有直接使用函数递归,但是使用了栈,所以实际上仍然是递归的思想。但是它递归的是那么朦胧,让人无法捉摸。可以从以下几个方面思考:首先,三个非递归遍历的算法开始都是向左走到树的最左下方的节点,并把路上遇到的节点入栈,这其实就是递归中的前一半过程。如下图所示:图中上半部分表示了一个递归函数的层层深入的栈结构,下面则是模拟了将二叉树的节点入栈的过程。以此类推,从最左下的节点向上的过程就是退栈的过程,也
阅读全文
posted @
2011-05-11 22:56
微型葡萄
阅读(2479)
推荐(1)