随笔分类 -  算法

摘要:先看一道面试题:长度为n的数组,由数字1到n组成,其中数字a不出现,数字b出现两次,其它的数字恰好出现一次。怎样通过只读遍历一次数组,找出数字a和b。由于只能遍历一次,在遍历数组arr时,算出 a和b的差值,以及a和b的平方差,通过解方程,即可求得a和b。具体做法为:设: s1 = 1 + 2 + ... + n (= n * (n + 1) / 2) s2 = arr[0] + arr[1] + ... + arr[n - 1] r1 = 1 + 4 + ... + n^2 (= n * (n + 1) * (2 * n + 1) / 6) r2 = arr[0]^2 + arr[1]^2. 阅读全文
posted @ 2012-03-20 21:07 flyinghearts 阅读(5710) 评论(0) 推荐(0)
摘要:http://www.cppblog.com/flyingheartshttp://www.cnblogs.com/flyingheartshttp://blog.csdn.net/flyingheartspdf版本下载㈠ Fibonacci数 刚接触Fibonacci数的时候,在网上看到“矩阵法”,看到要先实现一个矩阵乘法,感觉太麻烦了。后来仔细观察Fibonacci数列,发现有下面的规律: F(n) = F(k)*F(n+1-k) + F(k-1)*F(n-k) => F(2*n) = F(n+1) * F(n) + F(n) * F(n - 1) F(2*n+1) = F(n... 阅读全文
posted @ 2012-02-28 22:17 flyinghearts 阅读(1257) 评论(2) 推荐(0)
摘要:喝汽水问题 by flyinghearts 有1000瓶汽水,喝完后每3个空瓶能换1瓶汽水,问最后最多可以喝几瓶汽水,此时剩余几个空瓶? 不妨假设,共有n瓶汽水,每a个空瓶能换b瓶汽水(a > b)。刚开始有n瓶汽水,喝完后就有n个空瓶,多喝的汽水是靠空瓶换来的,每进行一次空瓶换汽水,就能多喝b瓶汽水、空瓶数目就减少了a-b个(a个空瓶换了b瓶汽水,喝完后得到b个空瓶)。 (下面用 [x] 表示x的整数部分) 1 如果允许从别处(老板或其他顾客处)借空瓶(当然,有借有还) 空瓶换汽水次数: [n / (a - b)] 最后剩余空瓶: n % (a - b) ... 阅读全文
posted @ 2011-09-23 19:49 flyinghearts 阅读(2211) 评论(0) 推荐(0)
摘要:前一篇文章讨论了二维坐标系下的判断,下面讨论三维的情况。 三维坐标下,对点的判断明显要复杂很多。如果google“Point in triangle”,第一个搜索结果就是这个网页,可惜的是,作者没有对结果进一步讨论,没有给出一个好的实现,而且其所有结论只在已知四点共面时才成立。 前面已经证明过,面积法和向量同向法是等价的。 ab × ac = ab × ap + ap × ac + pb × pc |ab × ac| = |ab × ap| + |ap × ac| + |pb × pc| 由于ab × a 阅读全文
posted @ 2011-07-14 23:27 flyinghearts 阅读(2034) 评论(1) 推荐(1)
摘要:问题:判断点P是否在三角形ABC内 判断一个点是否在在三角形内,最常用的两种方法:面积法、向量同向法。算法虽然很简单,但要做到高效却不容易,要考虑到二维、三维的区别,还要考虑到坐标是用浮点数还是用整数来表示。 在二维平面上,问题相对简单,一般只需6次乘法计算。但在三维平面时问题要复杂很多,在网上看到的算法,一般都需要30次乘法计算(如果已知点P在平面ABC上,则需21次)。实际上,在三维坐标系下,可以做到增加1次比较,将乘法计算降到13次(如果点P在平面ABC上,则最多只要8次乘法计算)。 最常用的两种方法:面积法和向量同向法本质上是等价的。 向量同向法:若点P在三角形内,则三个向量:ab & 阅读全文
posted @ 2011-07-07 23:13 flyinghearts 阅读(10897) 评论(10) 推荐(0)
摘要:要将一个数组的所有元素向左旋转k位,通常有三种算法:算法1(分组交换):若a长度大于b,将ab分成a0a1b,交换a0和b,得ba1a0,只需再交换a1 和a0。若a长度小于b,将ab分成ab0b1,交换a和b0,得b0ab1,只需再交换a 和b1。不断将数组划分和交换,直到不能再划分为止。分组过程与求最大公约数很相似。读写内存各 n到2*n次算法2 (三次反转)利用ba=(br)r(ar)r=(arbr)r,先分别反转a、b,最后再对所有元素进行一次反转。读写内存各约2*n次算法3 (使用循环链)假设 n、k的最大公约数为M,则所有序号为 (i + j*k) % n (0<= i &l 阅读全文
posted @ 2011-05-27 21:00 flyinghearts 阅读(6465) 评论(5) 推荐(1)
摘要:全排列的hash函数,可以利用N位变进制,一般做法是用逆序数,但时间复杂度比较大。 设n位变进制数M,+i位逢i+1进一,显然M可表示的数的范围为[0, n!)共n!个 要生成n个数的排列,可以先从n个数挑一个,再从剩下的n-1个数挑一下,如此反复n次。 若最初的n个数是 0,1,2 ... n-1,第一次挑选的数是t,则可以将t放入到M的n-1位, 若第二次挑选的数是m,则 0 <= r <= n-1 且 r != t,当r等于n-1时, 不能将r放入到M的n-2位(可以放的最大数为n-2),但是注意到r值不可能为t, 该情况下将它的值改为t,得到的新r值肯定小等于n-2,因而可 阅读全文
posted @ 2011-05-08 22:00 flyinghearts 阅读(2120) 评论(0) 推荐(0)
摘要:树状数组的二叉树解释 阅读全文
posted @ 2011-04-11 23:48 flyinghearts 阅读(2912) 评论(2) 推荐(1)
摘要:思路: 先画一棵完全二叉树, 为节省空间,采用数组来实现。对这棵二叉树,叶子用于存放数据,节点用于统计叶子信息。通过下面的三种方法,进一步节省空间:1 节点只记录左子树叶子信息,右子树叶子信息通过当前节点和父节点等节点的值计算得出。 因而需要指定一个点,当作根节点的“父节点”,以便计算根节点右子树信息。 可以将根节点从1开始编号,对节点i,左孩子编号为2*i,右孩子编号为2*i+1,并用编号0记录整根树所有叶子的信息。2 对某些应用,叶子信息可以通过节点信息计算得出,因而不保存叶子信息,3 完全二叉树,边界要求为2^k,为了表示[0, n)这n个点,需要将n增加到2^k,实际上, 只要第n个叶 阅读全文
posted @ 2011-03-31 23:13 flyinghearts 阅读(1527) 评论(0) 推荐(0)
摘要:输出和为n的所有的连续自然数序列 如 n = 9: 9 4 5 2 3 4 《编程之美》的题目(2.21只考加法的面试题),去年曾经写过本题的代码,后来不知道把代码放哪里了。按以前的思路,重写了下代码,写完后翻了下书,结果发现与书上要求的还不一样。 假设,拆分成的数列为:m, m+1, … m+k-1 则 n = (m + m + k - 1) * k / 2或 2*n = (2*m + k - 1) * k 显然就是求2*n的所有因子,最简单的方法就是暴力搜索: 对公式2*n = (2*m + k - 1) * k 进行转变,可得下面几种方法: 方法一: 2*m + k – 1 = 2 *. 阅读全文
posted @ 2011-03-22 23:39 flyinghearts 阅读(2945) 评论(0) 推荐(2)
摘要:问题: 输出自然数n的所有因子假设 n = i * j(i <= j) , k = j – i >= 0 思路一: j = n / i>=i( 注意:i – int(n / i) 随着i的增大而增大,int(n/i)指n/i的整数部份)从i = 1 开始判断 i 是否能被n整除,当int(n / i) < i 时终止思路二:n = i * (i + k)=>k = (n – i * i) / i>= 0=> k = m / i >= 0 (设m = n – i * i)从i = 1 开始判断 i 是否能被m整除,当m < 0(即k < 阅读全文
posted @ 2011-03-22 23:37 flyinghearts 阅读(2915) 评论(0) 推荐(0)
摘要:问题:求1到n这n个整数间的异或值,即 1 xor 2 xor 3 ... xor n 记 f(x, y) 为x到y的所有整数的异或值。 对 f(2^k, 2^(k+1) -1) (注意文章中的 ^ 表示的是“幂”,xor 表示“异或”,or 表示“或”): 2^k 到 2^(k+1) -1 这2^k个数,最高位(+k位)的1个数为2^k, 若 k >= 1,则2^k为偶数,将这2^k个数的最高位(+k位)去掉,异或值不变。 因而 f(2^k, 2^(k+1) -1) = f(2^k - 2^k, 2^(k+1) -1 -2^k) = f(0, 2^k -1) 因而 f(0, 2^(k+ 阅读全文
posted @ 2011-03-22 23:36 flyinghearts 阅读(5849) 评论(0) 推荐(3)
摘要:又一次看到讨论“洗牌”算法的文章,奇怪不少人喜欢造轮子,但造的轮子却远没有STL的random_shuffle好用。 “洗牌”算法: 若某个序列里面的每个元素在每个位置已经等概率出现,那么新增加一个元素,只要新增加的元素和所有元素进行等概率交换,则新序列中每个元素在每个位置仍是等概率出现。 (若原来有n个元素,新增加的第n+1个元素在任一位置b的概率显然是1/(n+1),在同一位置b,原来的n个元素在该位置仍是等概率出现的,出现的概率为(1-1/(n+1))/n = 1/(n+1)。 也可以这样算:进行随机交换前,原来的某个元素在某个位置出现的概率为1/n,被交换的概率为1/(n+1),因而. 阅读全文
posted @ 2011-03-22 23:34 flyinghearts 阅读(479) 评论(0) 推荐(1)
摘要:《编程之美》读书笔记12: 3.8 求二叉树中节点的最大距离 问题: 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。 实际上就是求树的直径。若采用“动态规划方法”思想,会将该问题分解成“具有最大距离两点间的路径是否经过根节点”两个子问题,然后再对这两个子问题求解判断。实际上,不必这么麻烦。距离最远的两点必然在以某个节点A为根的子树上,它们间的路径必然经过该子树的根节点A。因而,以任意一个节点B为根的子树,计算出经过该子树根节点B的最大距离,则所有最大距离的最大值就是 阅读全文
posted @ 2011-03-22 23:27 flyinghearts 阅读(2023) 评论(1) 推荐(0)
摘要:问题: N个1到13之间的自然数,能否通过加减乘除计算(每个数有且只能用一次)得到24? 计算24点常用的算法有:① 任取两个数,计算后,将结果放回去,再从剩下的数中任取两个,如此反复直到只剩下一个数;② 先构建前缀/后缀表达式,再计算该表达式;③ 用集合保存中间结果,集合间两两进行合并计算得到新集合(或者对给定的一个集合,对其所有的子集合进行合并计算)。 本文采用第一种方法。定义六种操作符:ADD、SUB、MUL、DIV、RSUB、RDIV,分别对应加、减、乘、除、反减和反除(反减/除:先交换两个数,再减/除)。 显然,取两个数计算时,六种计算结果可能有重复,可以对这6个结果进行去重(实 阅读全文
posted @ 2011-01-08 21:15 flyinghearts 阅读(4709) 评论(1) 推荐(1)
摘要:实际上,用树的后序遍历就可以了。当访问到所求的节点A时,如果这两个节点不在一条线上,则它们必定分别在A的左子树和右子树上,后序遍历到第一个满足这个条件的节点就是所要求的节点A。另外,还必须对这两个节点在一条线上的情况,做特殊处理。代码: staticboollca(Node*root,intva,intvb,Node*&result,Node*parrent){//left/right左/右子树是否含有要判断的两节点之一boolleft=false,right=false;if(!result&&root-left)left=lca(root-left,va,vb,result,root 阅读全文
posted @ 2011-01-01 00:13 flyinghearts 阅读(2948) 评论(0) 推荐(0)
摘要:Trilogy公司的笔试题: 如果n为偶数,则将它除以2,如果n为奇数,则将它加1或者减1。问对于一个给定的n,怎样才能用最少的步骤将它变到1。 例如:n=11: ① ++n - 12 ② n/2 - 6 ③ n/2 - 3 ④ --n - 2 ⑤ n/2 - 1 共需5步。 最简单的方法就是用DP。设f(n)为所用的最少步骤。根据定义可得: 若n为偶数, f(n)=f(n/2) + 1; 若n为奇数, f(n)= min(f(n-1), f(n+1)) +1 = min(f((n-1)/2), f((n+1)/2)) +2 或者: f(2*k)=f(k)+1 f(2*k+1)= 阅读全文
posted @ 2011-01-01 00:12 flyinghearts 阅读(455) 评论(0) 推荐(0)
摘要:多重背包O(N*V)算法详解(——使用单调队列) 多重背包问题: 有N种物品和容量为V的背包,若第i种物品,容量为v[i],价值为w[i],共有n[i]件。怎样装才能使背包内的物品总价值最大? 网上关于“多重背包”的资料倒是不少,但是关于怎么实现O(N*V)算法的资料,真得好少呀,关于“单调队列”那部分算法,又没说明得很清楚,看了几遍没看懂原理,只好自己动脑去想怎么实现O(N*V)算法。 若用F[i][j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m[i] = min(n[i], j / v[i])。放入背包的第i种物品的数目可以是:0、1、2……,可得: 阅读全文
posted @ 2011-01-01 00:10 flyinghearts 阅读(1022) 评论(4) 推荐(1)
摘要:问题: 一共有25匹马,有一个赛场,赛场有5个赛道,就是说最多同时可以有5匹马一起比赛。假设每匹马都跑的很稳定,不用任何其他工具,只通过马与马之间的比赛,试问最少得比多少场才能知道跑得最快的5匹马? 思路: 先将25匹马分成五组,进行五场比赛。第六场比赛可以考虑都取各个小组的第一名(或第二名)。假设都取各小组的第一名,根据这场比赛的排名,将原来的小组分别编号为a、b、c、d、e,并将原来的25匹马分别编号为: a1b1c1d1e1 a2b2c2d2e2 a3b3c3d3e3 a4b4c4d4e4 a5b5c5d5e5 其中Xi,X表示组的编号,i为在该组的排名,则有:a1 b1 c1 阅读全文
posted @ 2011-01-01 00:05 flyinghearts 阅读(1444) 评论(2) 推荐(1)
摘要:题目: 给出sum、min、max和n四个正整数,请输出所有将sum拆分为n个递增的正整数(允许相等)之和,其中每个正整数k都满足:min = k = max。 在少侠的博客看到这道题,就随手做了下。该题与输出N个数取M个数的所有组合类似,只不过限定了M个数的和以及取值范围。可以先用贪心算法构造一个最小的组合,然后调整这个组合,得到下一个组合。显然应该从后往前找到一个数字,该数增加1,再调整该数后面的数。这个数就是:从后往前第一个与最后一个数的差值大于1的数(因为,如果差值小等于1,无法调整后面的数得到一个符合要求的组合)。 [代码] 阅读全文
posted @ 2010-12-31 23:39 flyinghearts 阅读(1188) 评论(0) 推荐(0)