
算法
五道口纳什
wx公众号/B站:五道口纳什
展开
-
三个瓶盖能换一瓶水,问100个人需要喝水,最少需要买多少瓶水即可解决100人的喝水问题
三个瓶盖能换一瓶水,问100个人需要喝水,最少需要买多少瓶水即可解决100人的喝水问题原创 2016-01-17 20:20:18 · 7177 阅读 · 1 评论 -
如何判断两个矩形相交
如何判断两个矩形相交假定矩形是用一对点表达的(minx, miny) (maxx, maxy),那么两个矩形 rect1{(minx1, miny1)(maxx1, maxy1)} rect2{(minx2, miny2)(maxx2, maxy2)} 相交的结果一定是个矩形,构成这个相交矩形 rect{(minx, miny) (maxx, maxy)}的点对坐标是: minx =原创 2016-01-20 12:06:50 · 2168 阅读 · 0 评论 -
每周一刷——从斐波那契数列到动态规划
在csdn上看到一篇博客,博客的内容有有关图像方面的paper,有有关机器学习的理论推导和python实践,文风简洁而不拖沓,非常喜欢,仿佛找到了同类,翻到“about me”以及一些求职的博文,方向选择之困惑,在求学期间学习方法之反思(实践、实践、还是实践)。仿佛看到了自己,看到了自己的明天,这位博主对算法之深刻,找工作之路尚感艰难,何况我呢。顿感企业要求之高(基础之看重),算法学习之路艰辛,学习之法之重要。原创 2015-10-12 20:10:35 · 6843 阅读 · 3 评论 -
斐波那契数列与黄金分割比以及矩阵形式推导
数学上,斐波那契数列以递归的形式进行定义: F 0 =0F 1 =1F n =F n−1 +F n−2 \begin{split}&F_0=0\\&F_1=1\\&F_n=F_{n-1}+F_{n-2}\end{split}注意,递归的形式实现较为简单明了,当然在编程实践时,并不推荐递归的实现方式,因为存在大量的重复计算,斐波那契的优化实现不是本文的重点,如有兴趣,请参阅 每周一原创 2016-01-23 12:35:40 · 6537 阅读 · 0 评论 -
"生日悖论"补充
从排列与组合的python实现到”生日问题”的解释首先定义我们的记号(notation),用整数 i=1,2,…,k i=1,2,\ldots,k 来对房间里的人进行编号,其中 k k是房间里的总人数。不考虑闰年,所有的年份都是 n=365 n=365,令 b i b_i表示第 i i个人的生日。我们假设每个人的生日是独立的(这是一个重要假设),则 i i 和 j j 生日落在同一天 r r 的概原创 2016-01-24 12:42:10 · 2091 阅读 · 0 评论 -
取模运算与hash function
取模运算常常对应于hash散列;错误的 m,常得到错误的hash散列,错误的hash散列,则无法达到选取hash散列的目的;原创 2016-01-24 15:55:19 · 2599 阅读 · 0 评论 -
十进制小数<==>二进制小数
十进制小数 ⇒ 二进制小数二进制小数 ==> 十进制小数python实现原创 2016-01-24 21:45:18 · 2154 阅读 · 1 评论 -
循环结构的分析
如果抛开这道题目的迷惑性(它问的是几条 print 语句,而不是打印输出几条hello),问该程序打印输出多少hello呢?尤其注意第三个for循环,它与第二个for循环是相辅相成的,两个for循环(i,j)加在一起执行的次数== j执行的次数+j执行的次数 * k执行的次数。 所以本题: 1+1×(n−1)+2+2×(n−2)+3+3×(n−3)+⋯(n−1)+(n−1)×1+n1+1\ti原创 2016-01-25 12:36:37 · 1214 阅读 · 0 评论 -
扩展欧几里得算法及其应用
可公度线段与欧几里得(Euclid)算法 扩展欧几里得算法是欧几里得算法(又叫辗转相除法)的扩展。已知整数 a,ba,b,扩展欧几里得算法可以在求得 a,ba,b 的最大公约数(gcd(a,b)gcd(a,b))的同时,能找到整数 x,yx,y(其中一个很可能是负数)(贝祖等式告诉等式有解),使它们满足 Bézout’s identity(贝祖等式),d=gcd(a,b)=ax+byd=gcd(a,原创 2016-01-27 11:36:37 · 4744 阅读 · 0 评论 -
"3升5升得4升"——倒水问题的万能解法(扩展欧几里得算法)
扩展欧几里得算法及其应用 问题:假设你有一个3升的容器和一个5升的容器(以及充足的水源),如何精确地取出4升水来?(为了下文叙述的方便,我们不妨把3升的容器和5升的容器分别记做容器A和容器B)。这里提供一种解法:将A装满(3升),全部倒入B再次将A装满(3升),用A中的水将B装满,此时A有1升,B有5升B中的水全部倒出,将A中的1升水倒入B,此时A没有水,B有一升再次将A装满(3升),将A中原创 2016-01-27 15:26:35 · 43294 阅读 · 3 评论 -
素数的判断
为了判断一个数是不是素数(质数),最笨的方法就是试除法——原创 2016-01-29 21:20:03 · 2430 阅读 · 0 评论 -
"反复平方"——快速计算一个数的平方
“反复平方”可以快速计算出一个数的平方,比方说,计算 a35a^{35},相当于计算 a34⋅aa^{34}\cdot a,也即 (a17)2⋅a(a^{17})^2\cdot a,也即(a16⋅a)2⋅a(a^{16}\cdot a)^2\cdot a,…, 最终简化为 ((((a2)2)2)2⋅a)2⋅a((((a^2)^2)^2)^2\cdot a)^2\cdot a,我们可从中清晰地看到递归原创 2016-01-29 23:24:34 · 2545 阅读 · 0 评论 -
hash function/ hash table 背后的数学基础
原文请见:Load Balancing and the Power of Hashing如果你参加一次软件工程师的面试并你被问到一个很难的有关算法的题目,那么你最好考虑使用散列函数(hash tables)?更简洁地说吧:谷歌喜欢散列函数(and BAT)。要想知道为什么散列函数如此有用,你多少应该知道它里面的数学。一些概念术语的阐述load factor(装填因子)n keys, m slots原创 2016-01-23 10:12:56 · 2470 阅读 · 0 评论 -
hash function/ hash table 背后的数学基础(二)
hash function/ hash table 背后的数学基础 perfect hashing(完美哈希)给定 nn 个键,构建一个静态表(static hash table,也即没有插入和删除),表的大小是 m=O(n)m=O(n),使得在最坏的情况下,查找的时间是 O(1)O(1)。思路是使用一个二级结构(two-level scheme),在每一级上都使用全域哈希(universal ha原创 2016-01-31 16:03:43 · 1362 阅读 · 0 评论 -
随机矩阵(stochastic matrix)与 PageRank
随机矩阵实际上是一种特殊的非负矩阵(non-negative matrix),非负矩阵是指矩阵元素都是非负(non-negative)的,当然非负要与正矩阵(Positive Matrix,所有元素都大于0)进行细微的区分。References[1] 随机矩阵(stochastic matrix)原创 2016-02-01 14:42:44 · 12382 阅读 · 0 评论 -
从二分逼近领略计算科学的魅力
计算分两种: 数学家们的方法(倾向于给出解析解), 计算机科学家的方法(设计算法,重复的操作交给CPU)比如针对实数域上的函数 f(x)f(x),如果存在实数 x0x_0 使得 f(x0)=0f(x_0)=0,则 x=x0x=x_0 是函数 f(x)f(x)的零点。如果函数 f(x)f(x)是连续函数,且在区间 [x1,x2][x_1,x_2]上是单调函数,只要 f(x1)f(x2)<0f(x_原创 2016-01-08 22:42:14 · 3259 阅读 · 0 评论 -
平方根的计算(二分逼近、牛顿拉普生法)
在从二分逼近领略计算科学的魅力一文中,我们介绍了单调函数的求根公式(有零点),如 f(x)=2x2+3.2x−1.8f(x)=2x^2+3.2x-1.8。我们能否采用二分逼近的原理,求解一个数的平方根(x2=nx^2=n)呢,自然地,我们将 x2=nx^2=n 转换为求解 f(x)=x2−nf(x)=x^2-n 的零点,也即根,在 [0,n][0,n] 的区间上,f(x)=x2−nf(x)=x^2-原创 2016-02-15 16:59:38 · 7718 阅读 · 1 评论 -
一行代码进行闰年的判断
所谓闰年,一种简化的判断方法即是,能被4整除,如果能被100整除,而无法被400整除,这不是闰年: 所以其一贯的判断逻辑即是:def isleap(y): if y % 4: return False if y % 100 == 0 and y % 400 != 0: return False return True判断逻辑较为复杂,稍作思考原创 2016-02-15 23:08:03 · 3305 阅读 · 0 评论 -
从一个实例(整数幂指数)进行算法时间复杂度的分析
算法的时间复杂度在于基本步骤(basic steps)的考量。 复杂度 notation 描述 常量(Constant) O(1)O(1) 基本操作的数量为常数,与输入数据的规模无关n=10^6 ⇒ 1-2 operations 对数(Logarithmic) O(logn)O(\log n) 操作的数量为 log2n\log_2nn=10^6 ⇒ 30 operat原创 2016-02-16 18:31:39 · 7867 阅读 · 0 评论 -
从“递归结构”到解汉诺塔问题的求解
汉诺塔这一著名的递归问题。解决递归问题的关键在于寻找递归的结构。比如斐波那契数列的递归结构是什么:原创 2016-02-16 12:30:55 · 1201 阅读 · 0 评论 -
搜索——二分搜索实现及细节
二分搜索,又叫折半搜索算法,其原理较为简单,不再赘述,其时间复杂度为 O(logn)O(\log n)。本文重在细节的一些说明,递归和循环两个版本的实现循环退出的条件l > hmiddle 值的选取(不溢出)m = l + (h-l)//2# 递归版本def bisearch(s, e, l, h): if l > h: return False m =原创 2016-02-17 10:51:05 · 928 阅读 · 0 评论 -
排序——选择排序
选择排序是符合直观(接近直观)的排序,第一次内层循环选出最小的元素放在第一的位置,第二次内层循环从余下的元素选出最小的元素放在第二的位置,以此类推。原创 2016-02-17 12:15:28 · 1036 阅读 · 0 评论 -
排序——归并排序
排序——选择排序 排序——冒泡排序及其改进版本原创 2016-02-17 12:38:04 · 1119 阅读 · 0 评论 -
直接无序搜索 vs 先排序后搜索
算法的时间复杂度分析和算法流程共同构成算法本身,如果一个算法的时间复杂度是指数级O(2^n)的,当面对海量数据处理时,将是灾难性的。排序——冒泡排序及其改进版本 排序——选择排序 排序——归并排序 对一个有序数列,我们使用二分搜索(binary search),可以获得 O(logn)O(\log n) 的时间复杂度;对一个无序数列,我们采用遍历判断的方法(linear),时间复杂度为:O(n原创 2016-02-17 15:05:18 · 1566 阅读 · 0 评论 -
算法——贪心算法解0-1背包问题
问题的描述我们先根据一个贪心算法的经典应用实例,然后给出贪心算法的实现步骤与关键环节,最后给出C++代码求解0-1背包问题。 背包问题(Knapsack Problem):有NN件物品有一个承重(也可受限于体积)为CC的背包,每件物品具有二维属性,分别是重量属性wi,i=1,…,Nw_i,\quad i=1,\ldots,N,和价值属性pi,i=1,…,Np_i,\quad i=1,\ldots原创 2015-11-21 10:57:27 · 14473 阅读 · 0 评论 -
从0-1背包问题到动态规划
算法——贪心算法解0-1背包问题 局部最优策略(locally optimal decisions,比如贪心算法),并不保证全局最优(global optimums)“在我的后园,可以看见墙外有两株树,一株是枣树,还有一株也是枣树。”,同样如果有两个手表,为了达到0/1背包问题的要求,也可转化为一个手表,还有一个手表。brute force(暴力法)的本质是 exhaustive enumer原创 2016-02-17 17:35:55 · 1805 阅读 · 0 评论 -
STL::算法::常见算法
总述定位泛型编程(GP)走了一条与面向对象编程(OOP)完全不同的道路,各种容器类的设计与实现也没有走严格意义的继承、接口机制。在STL的设计与实现中,算法并非是容器类的成员函数,而是一种搭配迭代器(架起沟通算法和容器类的桥梁)使用的全局函数。这样做的一个重要优势在于:所有算法只需实现一份(而不是在每一个容器类的内部都实现一份),就可以对所有容器运作,不必为每一个容器类量身定制。因为算法本身也是模板原创 2015-11-11 21:11:26 · 1355 阅读 · 0 评论 -
【剑指offer】(七)—— 用两个栈实现队列
题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead,分别完成在队尾插入节点和在队列头部删除节点的操作。template<typename T>class CQueue{public: void appendTail(const T& elem); T deleteHead();private: stack<T原创 2016-03-29 17:16:27 · 963 阅读 · 0 评论 -
【剑指 offer】—— 快速排序
两个辅助函数:// 生成区间内的随机整数int RandInRange(int s, int e, unsigned seed=time_t(0)){ srand(seed); return rand()%(e-s)+s;}void Swap(int& a, int& b){ int tmp = a; a = b; b = tmp;}分区函数:int partit原创 2016-03-29 20:33:38 · 1484 阅读 · 0 评论 -
【剑指 offer】—— 为公司员工的年龄排序
快速排序虽然总体的平均效率是最好的,但也不是在任何时候都是最优的算法。比如数组本身已经是排好序了,而每一轮排序的时候都是以最后一个数字作为比较的标准,此时快速排序的效率只有 O(n2)O(n^2)。因此在这种场合快速排序就不是最优的选择。考虑如下的场景,如何以时间效率 O(n)O(n) 实现对公司员工年龄的排序,公司共有几万名员工。其实公司员工的年龄只在一个很小的区间内变化(range),又因为有那原创 2016-03-29 21:11:57 · 1502 阅读 · 0 评论 -
【剑指 offer】(十)—— 二进制形式 1 的个数
可能引起死循环的解法int numOf1(int n){ int cnt = 0; while (n) { if (n & 1) ++cnt; n >>= 1; } return cnt;}把整数右移一位和把整数除以 2 在数学上是等价的,那上面的代码可以把右移运算换成除以 2 吗?答案是否定的。因为原创 2016-03-29 21:54:08 · 987 阅读 · 0 评论 -
Trick(一)——判断一个数的位数
传统的做法是,不断地除以10,def digits(n): cnt = 0 while n: cnt += 1 n //= 10 return cnt在微博上看到一种较为数学(也较为tricky)的方法,使用 log10\log_{10}(以10为底,而) 映射的结果即为该数的位数,x=1∼9x=1\sim9:0<log10x<10<\log原创 2016-03-16 15:08:52 · 2266 阅读 · 0 评论 -
算法——从旋转字符串到翻转单词
一、字符串的旋转描述:给定一个字符串,要求将字符串前面的若干字符移到字符串的末尾。例如,将字符串的 “abcdef” 的前面 3 个字符 ‘a’, ‘b’ ‘c’ 移到字符串的末尾,那么原字符串将变成 “defabc”。解法一:蛮力移位(循环左移)较为直观的一种解法即是,将需要移动的字符使用循环左移(ROL,Ring Shift Left)的方式一个一个地移到字符串的尾部。// 循环左移 1 位,循原创 2016-03-20 23:00:11 · 1230 阅读 · 0 评论 -
Python 数据结构与算法——tree(树)
(1)节点:Node、根节点:Root、叶子节点:LeafNode、内部节点:InternalNode; 我们可将该树表示为一个二维列表(lists of lists):>>> T = [['a, b'], ['c'], ['d', ['e', 'f']]]在某些情况下,由于我们可能事先知道其内部节点(Internal Node)所能拥有的最大子节点数,例如,二叉树,各节点最多只能拥有两个子原创 2016-03-21 09:03:40 · 23300 阅读 · 0 评论 -
Python 数据结构与算法——归并排序
排序——归并排序 上文的 Python 实现还是稍显啰嗦,未能充分发挥 Python 语言的优势,以及“Python——一种可执行的伪代码”的论断。本文介绍一种更为简洁的归并排序的实现:def mergesort(l): m = len(l)//2 lft, rgt = l[:m], l[m:] if len(lft) > 1: lft = mergesort(lft)原创 2016-03-21 10:23:43 · 1465 阅读 · 0 评论 -
Python 数据结构与算法——侏儒排序
侏儒排序作为排序算法的历史地位远不及对其进行时间复杂度分析的地位来得高。def gnomesort(l): i = 0 while i < len(l): if i == 0 or l[i-1] <= l[i]: i += 1 else: l[i-1], l[i] = l[i], l[i-1]原创 2016-03-21 11:06:51 · 1734 阅读 · 0 评论 -
Python 数据结构与算法——从某个列表中找出两个彼此最接近但不相等的数
先排序,再。。。(毕竟归并排序的时间复杂度仅为 O(nlogn)O(n\log n))排序的幽灵。排序和查找真是一对好基友。来看基础版本:from random import randrangeseq = [randrange(10**10) for _ in range(100)]dd = float('inf')for x in seq: for y in seq:原创 2016-03-21 12:49:59 · 7812 阅读 · 3 评论 -
【笔试/面试】—— 序列全排列(递归版)
void perm(int seq[], int k, int m){ if (k == m) { copy(seq, seq+m, ostream_iterator<int>(cout, " ")); cout << endl; return; } for (int i = k; i < m; ++i) {原创 2016-04-02 17:26:37 · 1036 阅读 · 0 评论 -
数学归纳法与算法设计
归纳法其实是先提出一个问题或语句 P(n)P(n),再来证明其对任何自然数 nn 都成立,例如,我们要考察的是前 nn 个奇数之和,那么其 P(n)P(n) 可能会是以下这条语句: 1+3+5+⋯+(2n−1)=n21+3+5+\cdots+(2n-1)=n^2 归纳法的思路是建立起一条涵盖所有自然数的“扫描式”证据链(推导链),该过程有点类似于一排多米诺骨牌倒下时的情况。P(1)P(1)原创 2016-03-21 14:33:53 · 2568 阅读 · 0 评论 -
Python 数据结构与算法——插入排序(insertion sort)
我们先归纳性地假设前 n−1n-1 个元素已经完成排序,现在要将第 nn 个元素插入到正确位置。如下为递归版的插入排序的代码清单:# n == len(seq)-1, seq[n] 表示序列的最后一个元素def ins_sort_rec(seq, n): if n == 0: return ins_sort_rec(seq, n-1) j = n while j原创 2016-03-21 15:02:47 · 2571 阅读 · 0 评论