随笔分类 -  数据结构与算法

找出无序数组中第k小的数
摘要:题目描述:给定一个无序整数数组,返回这个数组中第k小的数。解析:最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1)。使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n)。代码实现:#include <iostream>#include <string>#include <cstring>#include <vector>#include <algorithm>using namespace std;void sw 阅读全文

posted @ 2012-10-05 01:37 as_ 阅读(4421) 评论(3) 推荐(2) 编辑

O(n)回文子串(Manacher)算法
摘要:资料来源网络 参见:http://www.felix021.com/blog/read.php?2040问题描述:输入一个字符串,求出其中最大的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同,如abba和yyxyy。解析:这里介绍O(n)回文子串(Manach... 阅读全文

posted @ 2012-10-04 16:23 as_ 阅读(31118) 评论(6) 推荐(2) 编辑

编辑距离及编辑距离算法
摘要:编辑距离概念描述:编辑距离,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。例如将kitten一字转成sitting:sitten (k→s)sittin (e→i)sitting (→g)俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。问题:找出字符串的编辑距离,即把一个字符串s1最少经过多少步操作变成编程字符串s2,操作有三种,添加一个字符,删除一个字符,修改一个字符解析:首先定义这样一个函数——edit(i, j),它表示第一个字符串的长度为i 阅读全文

posted @ 2012-09-28 16:05 as_ 阅读(65940) 评论(7) 推荐(10) 编辑

编程之美:寻找发帖"水王"
摘要:1.问题描述快速找出发帖超过一半的的ID问题变型:现在有一个数组,已知一个数出现的次数超过了一半,请用最小的复杂度的算法找出这个数。问题扩展:有三个发帖很多的ID,他们的发帖数目超过了帖子总数目的1/4,请从发帖ID列表中找出它们2.分析与解法每次从列表中删除两个不同的ID,那么剩下的ID列表中,“水王”的ID出现次数仍然超过剩余数目的一半,因此每次删除两个不同的ID,直到剩下的所有ID都相同,那么剩下的就是水王的ID。我们可以设置一个candidate和一个计数器nTimes,candidate为ID列表第一个ID,nTimes初始值为0,遍历整个ID列表,当遍历的ID与candidate相 阅读全文

posted @ 2012-08-19 13:10 as_ 阅读(806) 评论(0) 推荐(0) 编辑

编程之美:求二叉树中节点的最大距离
摘要:1.问题描述写一个程序求一棵二叉树相距最远的两个节点之间的距离如下图:2.分析与解法对于任意一个节点,以该节点为根,假设这个根有k个孩子节点,那么距离最远的两个节点U与V之间的路径与这个根节点的关系有两种。1).若路径经过Root,则U和V属于不同子树的,且它们都是该子树中到根节点最远的节点,否则跟它们的距离最远相矛盾2).如果路径不经过Root,那么它们一定属于根的k个子树之一,并且它们也是该子树中相距最远的两个顶点因此,问题就可以转化为在字数上的解,从而能够利用动态规划来解决。设第K棵子树中相距最远的两个节点:Uk和Vk,其距离定义为d(Uk,Vk),那么节点Uk或Vk即为子树K到根节点R 阅读全文

posted @ 2012-08-18 14:50 as_ 阅读(5126) 评论(0) 推荐(1) 编辑

编程之美:从无头单链表中删除节点
摘要:1.问题描述假设有一个没有头指针的单链表。一个指针指向此单链表中间的一个节点(不是第一个,也不是最后一个),请将该节点从单链表中删除。如下图所示:2.分析与解法假设给定的指针为pCurrent, Node* pNext = pCurren->next其中pCurren->next!=NULL,如下图,因为没有头结点,删除pCurren指向的节点B就很困难,而删除节点C就非常容易,于是就现将节点C当中的数据等信息拷贝到节点B上,覆盖节点B原来的数据,然后删除节点C。删除之前删除之后3.代码实现struct Node{ int data; Node* next;}; voi... 阅读全文

posted @ 2012-08-18 13:26 as_ 阅读(665) 评论(0) 推荐(0) 编辑

编程之美:无差错二分查找
摘要:1.虽然二分查找是十分简单的程序,但是因为循环等操作也是最容易出错的,其中在写循环(或者递归)程序的时候,应该特别注意三个方面的问题:初始条件、转化、终止条件。2.二分查找源码int biseach(char** arr, int b, int e, char* v){ int minIndex = b, maxIndex = e, midIndex; while(minIndex < maxIndex - 1) //若改为minIndex < maxIndex时,容易出现死循环 { ... 阅读全文

posted @ 2012-08-18 10:05 as_ 阅读(906) 评论(0) 推荐(0) 编辑

编程之美:编程判断两个链表是否相交
摘要:1.问题描述给出两个单向链表的头指针,比如h1、h2,判断两个链表是否相交。编程之美为了简化问题,假设两个链表均不带环。如下图:2.分析与解法解法一:直观法,先判断第一个链表的每个节点是否在第二个链表中,这种方法时间复杂度为O(Length(h1)*Length(h2))解法二:hash表计数法,首先将第一个链表的所有节点地址进行hash排序,建立hash表,然后针对第二个链表的每个节点的地址,查询hash表,如果它在hash表中存在,那么说明两个链表有交点。这个方法时间复杂度O(Length(h1)+Length(h2)),空间复杂度O(Length(h1))。解法三:转换为是否有环问题,可 阅读全文

posted @ 2012-08-17 14:54 as_ 阅读(2820) 评论(0) 推荐(0) 编辑

编程之美:求数组的子数组之和的最大值
摘要:1.问题描述一个有N个整数元素的一维数组( A[0], A[1], ... , A[n-2], A[n-1]),子数组之和的最大值是什么?(要求子数组的元素是连续的)例子:有数组( -2, 5, 3, -6, 4, -8, 6),则其子数组之和的最大值为8,其对应的数组为(5,3)2.分析与解法解法一:采用直接法,记Sum[i...j],为数组A中从第i到第j之间所有数之和,算出所有Sum,取其最大,代码如下,时间复杂度O(N2):int maxSum1(int *A, int n){ int max = -1; int i, j, sum; for(i = 0; i... 阅读全文

posted @ 2012-08-17 13:28 as_ 阅读(4756) 评论(3) 推荐(0) 编辑

编程之美:阶乘数计算
摘要:1.问题描述1).给定一个整数N,那么N的阶乘N!末尾有多少个0?例如:N=0,N!=3628800,N!的末尾有两个0.2).求N!的二进制表示中最低1的位置2.分析与解法首先考虑,如果N! = K*10M,且K不能被10整除,那么N!末尾有M个0.再考虑对N!质因分解,N! = (2X)*(3Y)*(5Z)...,由于10=2*5,所以M只跟X和Z有关,每一对2和5都可以得到一个10,于是M=min(X,Z)。不难看出X大于等于Z,因为在N!分解的数种明显2出现的频率要高于5,所以把公式简化为M=Z。根据上面的分析,有对于问题1解法一:要计算Z,最直接的方法,就是计算i(i =1, 2, 阅读全文

posted @ 2012-08-17 09:58 as_ 阅读(657) 评论(0) 推荐(0) 编辑

编程之美:求二进制中1的个数
摘要:1.问题描述实现一个函数,输入一个无符号整数,输出该数二进制中的1的个数。例如把9表示成二进制是1001,有2位是1,因此如果输入9,该函数输出22.分析与解法解法1:利用十进制和二进制相互转化的规则,依次除余操作的结果是否为1 代码如下:int Count1(unsigned int v){ int num = 0; while(v) { if(v % 2 == 1) { num++; } v = v/2; } return num;}解法2:向右移位操... 阅读全文

posted @ 2012-08-16 14:45 as_ 阅读(4775) 评论(1) 推荐(1) 编辑

编程珠玑:旋转交换技巧
摘要:1.问题描述将一个n元一维向量向左旋转i个位置。例如,当n=8且i=3时,向量abcdefgh旋转为defghabc。简单的代码使用一个n元的中间向量在n步就能够完成该工作,你能否仅使用数十个额外字节的存储空间,正比于n的时间内完成向量旋转?2.解决思路旋转向量x其实就是交换向量ab的两段,得到向量ba。这里a代表x中的前i个元素。假设a比b短,将b分为bl和br,使得br具有与a相同的长度。交换a和br,也就是将ablbr 。序列a此时已处于其最终的位置,因此现在就集中到交换b的两部分。由于新问题与原来的问题具有相同的形式,我们可以递归地解决之。编程珠玑提供了更简单使用的方法,我们将问题看做 阅读全文

posted @ 2012-08-15 18:11 as_ 阅读(871) 评论(0) 推荐(0) 编辑

编程珠玑:取样问题
摘要:1.问题描述程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。从概率的角度说,我们希望得到没有重复的有序选择,其中每个选择出现的概率相等。2.解决思路与代码实现编程珠玑上给出了四个函数1).genknuth():算法依次考虑整数0,1,2,...,n-1,并通过一个适当的随机测试对每个整数进行选择。通过按序访问整数,可以保证输出结果是有序的代码C++实现:void genknuth(int m, int n) { for(int i = 0;i < 0;i++) { if((bigrand() % (n... 阅读全文

posted @ 2012-08-15 16:00 as_ 阅读(672) 评论(0) 推荐(0) 编辑

编程珠玑:用后缀数组寻找最长重复字符串
摘要:1.基本概念子串:字符串 S 的子串 r[i..j] , i ≤ j ,表示 r 串中从 i 到 j 这一段,就是顺次排列 r[i],r[i+1],...,r[j] 形成的字符串。后缀:后缀是指从某个位置 i 开始到整个串末尾结束的一个特殊子串。字符串 r 的从 第 i 个字 符 开 始 的 后 缀 表 示 为 Suffix(i) ,也 就 是Suffix(i)=r[i..len(r)] 。后缀数组:后缀数组 SA 是一个一维数组,它保存 1..n 的某个排列 SA[1] ,SA[2] , …… , SA[n] ,并且保证 Suffix(SA[i]) < Suffix(SA[i+1]) 阅读全文

posted @ 2012-08-15 14:19 as_ 阅读(3125) 评论(1) 推荐(0) 编辑

编程珠玑:单词频率最高选取
摘要:问题描述:对一个输入文本中的每个单词的出现次数统计,并选取出现频率最大的10个单词首先用C++实现,着重注意STL的map,vector排序用法,这里与编程珠玑的代码不同。不知道何故,编程珠玑上的代码, 输入之后得到的结果是按照单词排序的,而不是按照次数排序,这里做了修改C++实现代码:#include <iostream> #include <stdlib.h> #include <string> #include <map> #include <vector> #include <algorithm> using na 阅读全文

posted @ 2012-08-14 19:49 as_ 阅读(565) 评论(0) 推荐(1) 编辑

编程珠玑:变位词程序的实现
摘要:这个程序的实现有助于压缩key的大小,使查找效率更高1.问题描述 给定一本英语单词词典,请找出所有的变位词集。所谓的变位词是指,组成各个单词的字母完全相同,只是字母排列的顺序不同。2.解决思路编程珠玑的变位词程序要按照三个步骤来执行,其中前一个步骤程序的输出作为下一个步骤程序的输入:第一:程序标识单词,第二:程序排序标识后的文件,第三:程序将这些单词压缩为每个变位词类一行的形式下面是编程珠玑的举例,仅有6个单词的字典的处理过程由以上可看出需要三个程序的处理1).sign程序:假设输入单词的长度不超过100,对每个输入的单词依照字母进行排序,将结果输入这个单词所对应的”签名“2).sort程序: 阅读全文

posted @ 2012-08-14 15:42 as_ 阅读(3809) 评论(1) 推荐(1) 编辑

编程珠玑:位图法排序
摘要:问题描述输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=107。如果在输入文件中有任何正数重复出现就是致命错误。没有其他数据与该正数相关联。输出:按升序排列的输入正数的列表。约束:最多有1MB的内存空间可用,有充足的磁盘存储空间可用。运行时间最多几分钟,运行时间为10秒就不需要进一步优化。程序设计与实现概要:应用位图或位向量表示集合。可用一个10位长的字符串来表示一个所有元素都小于10的简单的非负整数集合,例如,可以用如下字符串表示集合{1,2,4,5,8}:0 1 1 1 0 1 0 0 1 0 0代表集合中数值的位都置为1,其他左所有的位置为0.编程珠玑当中建议是一年个一个具有 阅读全文

posted @ 2012-08-14 14:06 as_ 阅读(8841) 评论(1) 推荐(1) 编辑

贪心算法
摘要:以下参照一张清华PPT课件1.定义概览贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解算法思想:从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。该算 阅读全文

posted @ 2012-07-31 15:28 as_ 阅读(9882) 评论(0) 推荐(0) 编辑

最短路径—Dijkstra算法和Floyd算法
摘要:注意:以下代码 只是描述思路,没有测试过!! Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业 阅读全文

posted @ 2012-07-31 12:37 as_ 阅读(689037) 评论(49) 推荐(90) 编辑

最小生成树-Prim算法和Kruskal算法
摘要:Prim算法1.概览普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克 阅读全文

posted @ 2012-07-30 19:08 as_ 阅读(307732) 评论(17) 推荐(47) 编辑

导航