diff --git a/README.md b/README.md index 128b3ec..2295d50 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,17 @@ **二叉树** 二叉树 二叉查找树 -Trie树 +Trie树(前缀树) 后缀树 +最优二叉树(赫夫曼树) +伸展树(splay tree 分裂树) 平衡二叉树AVL 红黑树 B树(B-),B+,B* R树 -最优二叉树(赫夫曼树) -伸展树 -二叉堆 + +二叉堆 (大根堆,小根堆) 二项树 二项堆 斐波那契堆(Fibonacci Heap) @@ -42,7 +43,8 @@ KMP算法 BM算法 -**图的算法** +**图的算法** +图的存储结构和基本操作(建立,遍历,删除节点,添加节点) 最小生成树 拓扑排序 关键路径 @@ -52,36 +54,37 @@ BM算法 **排序算法(八大排序)** 快排 -插入排序 : 希尔排序 -选择排序 : 堆排序 -归并排序 -基数排序 - - +插入排序 : 希尔排序 +选择排序 : 堆排序 +归并排序 +基数排序 + + **查找算法** -静态查找: 顺序表查找,有序表查找, -动态查找: 二叉排序树,AVL树,B- ,B+ -哈希表: +顺序表查找:顺序查找 +有序表查找:二分查找 +分块查找: 块内无序,块之间有序;可以先二分查找定位到块,然后再到`块`中使用顺序查找(这里之所以叫 `动态查找表`,是因为表结构是查找的过程中动态生成的) +动态查找: 二叉排序树,AVL树,B- ,B+ +哈希表: O(1) **15个经典基础算法** -A*. -Dijkstra. -DP -.BFS/DFS. -红黑树. -KMP -.遗传算法. +A*寻路算法: 求解最短路径 +Dijkstra:最短路径算法 (八卦下:Dijkstra是荷兰的计算机科学家,提出”信号量和PV原语“,"解决哲学家就餐问题",”死锁“也是它提出来的) +DP (动态规划 dynamic programming) +BFS/DFS (广度/深度优先遍历) +红黑树 (一种自平衡的`二叉查找树`) +KMP 字符串匹配算法 +遗传算法 启发式搜索. -图像特征提取SIFT sift算法 -.傅立叶变换 -.Hash. +图像特征提取之SIFT算法 +傅立叶变换 +Hash 快速排序 -.SPFA. -快递选择SELECT - +SPFA(shortest path faster algorithm) 单元最短路径算法 +快递选择SELECT @@ -117,7 +120,7 @@ http://www.chinaunix.net/old_jh/23/437639.html *侧重经典算法的实现* -《Elements of Programming》 STL代码 快 准 狠 ,写出的代码可以上层次 +《Elements of Programming》 STL代码 快 准 狠 ,写出的代码可以上层次 《C interfaces and Implementation》 《The practice of programming》 Brian Kernighan和Rob Pike @@ -199,7 +202,7 @@ http://www.cs.usfca.edu/~galles/visualization/Algorithms.html http://leetcode.com/ http://oj.leetcode.com/ -http://openjudge.cn/ POJ。这有个POJ上的ACM训练方案 http://www.java3z.com/cwbwebhome/article/article19/res041.html +http://openjudge.cn/ POJ。这有个POJ上的ACM训练方案 http://www.java3z.com/cwbwebhome/article/article19/res041.html http://ac.jobdu.com/index.php 九度OJ diff --git a/算法问题选编/README.md b/算法问题选编/README.md index e69de29..91723db 100644 --- a/算法问题选编/README.md +++ b/算法问题选编/README.md @@ -0,0 +1,57 @@ + + + +###数值问题 + +这部分都是一些数学几何计算方面的问题。 + + +### 字符串 + +计算机处理的数据除了数值,就是字符。字符处理的常见问题包括: + +单词反转 +回文判断 +字符串的压缩 +字符串的排列和组合 + +字符串比较 +子串 + + +### 数组数列问题 + +数组 + +数列 + +矩阵 + + + +### 堆和栈 + + + + + +### 链表 + + + +### 二叉树 + + + +### 图 + + + +### 海量数据处理 + + + + + + + diff --git a/算法问题选编/二叉树.md b/算法问题选编/二叉树.md index 52b412d..efebf78 100644 --- a/算法问题选编/二叉树.md +++ b/算法问题选编/二叉树.md @@ -2,8 +2,8 @@ -1.把二元查找树转变成排序的双向链表 - 题目: +把二元查找树转变成排序的双向链表 + 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 @@ -67,19 +67,17 @@ BinaryTreeNode *m_pRight; // right child of node - - - -13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。 +设计一个算法,找出二叉树上任意两个结点的最近共同父结点。 复杂度如果是O(n2)则不得分。 -14、一棵排序二叉树,令 f=(最大值+最小值)/2, + +一棵排序二叉树,令 f=(最大值+最小值)/2, 设计一个算法,找出距离f值最近、大于f值的结点。 复杂度如果是O(n2)则不得分。 -第15题: + 题目:输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点。 用递归和循环两种方法完成树的镜像转换。 @@ -107,7 +105,7 @@ struct BSTreeNode // a node in the binary search tree (BST) -第16题: + 题目(微软): 输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。 例如输入 @@ -124,7 +122,7 @@ struct BSTreeNode // a node in the binary search tree (BST) -52.二元树的深度。 +二元树的深度。 题目:输入一棵二元树的根结点,求该树的深度。 @@ -167,22 +165,22 @@ struct SBinaryTreeNode // a node of the binary tree -43.递归和非递归俩种方法实现二叉树的前序遍历。 +递归和非递归俩种方法实现二叉树的前序遍历。 -5、怎样编写一个程序,把一个有序整数数组放到二叉树中? +怎样编写一个程序,把一个有序整数数组放到二叉树中? -6、怎样从顶部开始逐层打印二叉树结点数据?请编程。 +怎样从顶部开始逐层打印二叉树结点数据?请编程。 -2、有一棵树(树上结点为字符串或者整数),请写代码将树的结构和数据写到一个文件中,并能通过读取该文件恢复树结构 。 +有一棵树(树上结点为字符串或者整数),请写代码将树的结构和数据写到一个文件中,并能通过读取该文件恢复树结构 。 -75.二叉树两个结点的最低共同父结点 +二叉树两个结点的最低共同父结点 题目:二叉树的结点定义如下: struct TreeNode { @@ -194,3 +192,9 @@ struct TreeNode 输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。 分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。 + + + + + + diff --git a/算法问题选编/堆和栈.md b/算法问题选编/堆和栈.md index d602347..60bb850 100644 --- a/算法问题选编/堆和栈.md +++ b/算法问题选编/堆和栈.md @@ -1,5 +1,6 @@ + 如果用一个循环数组q[0..m-1]表示队列时,该队列只有一个队列头指针front,不设队列尾指针rear,求这个队列中从队列头到队列尾的元素个数(包含队列头、队列尾)(华赛面试题、腾讯笔试题)。 有rear指针时: diff --git a/算法问题选编/字符串.md b/算法问题选编/字符串.md index 43a652a..0100287 100644 --- a/算法问题选编/字符串.md +++ b/算法问题选编/字符串.md @@ -174,7 +174,6 @@ outputstr所指的值为123456789 -37. 有n个长为m+1的字符串, 如果某个字符串的最后m个字符与某个字符串的前m个字符匹配,则两个字符串可以联接, 问这n个字符串最多可以连成一个多长的字符串,如果出现循环,则返回错误。 @@ -223,18 +222,18 @@ hash方法。hash[128], O(N)复杂度 -2.编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将字符 +编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将字符 串 ”+123”123, ”-0123”-123, “123CS45”123, “123.45CS”123, “CS123.45”0 -85.又见字符串的问题 + 1.给出一个函数来复制两个字符串A和B。 字符串A的后几个字节和字符串B的前几个字节重叠。 分析:记住,这种题目往往就是考你对边界的考虑情况。 -2.已知一个字符串,比如asderwsde,寻找其中的一个子字符串比如sde的个数, +已知一个字符串,比如asderwsde,寻找其中的一个子字符串比如sde的个数, 如果没有返回0,有的话返回子字符串的个数。 char *sub_str_count(const char *src, const char *substr, int *count) @@ -255,7 +254,7 @@ int continuousnum(const char *input, char *output) -56.最长公共字串。 +最长公共字串。 题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中, diff --git a/算法问题选编/数值问题.md b/算法问题选编/数值问题.md index 9c53373..3da4d86 100644 --- a/算法问题选编/数值问题.md +++ b/算法问题选编/数值问题.md @@ -174,16 +174,8 @@ int one_appear_count(int n); - - - - - - 排列组合问题 - 1,2,3,4,5 五个不同的数字,打印不同的排列 - 这就是一个无向图的遍历,把每个数字看成一个节点。 diff --git a/算法问题选编/测试代码/string.c b/算法问题选编/测试代码/string.c index f859402..88fe732 100644 --- a/算法问题选编/测试代码/string.c +++ b/算法问题选编/测试代码/string.c @@ -163,7 +163,7 @@ char first_appear_only_once(const char *source){ int max_symmetrical_char_length(const char *scr){ int max_symmetrical_length=1; - + return 0; @@ -187,6 +187,7 @@ int continuousnum(const char *input, char *output){ + // 2个字符串的最长公共子串 int longest_common_subsequence(const char *s1,const char *s2, char *common){ diff --git a/算法问题选编/海量数据处理.md b/算法问题选编/海量数据处理.md index e450020..e264f09 100644 --- a/算法问题选编/海量数据处理.md +++ b/算法问题选编/海量数据处理.md @@ -6,7 +6,7 @@ 空间上:数据量太大,无法一次全部装入内存;针对方法是大而化小,分而治之。将规模大划分为规模小的问题,各个击破 -1. 分而治之/Hash映射 + hash统计 + 堆排序/快速排序/归并排序 +1. 分而治之/Hash映射 + hash统计/trie树/红黑树/二叉搜索树 + 堆排序/快速排序/归并排序 2. 双层桶划分 3. Bloom filter 、Bitmap 4. Trie树/数据库/倒排索引 @@ -16,9 +16,13 @@ ### 海量日志处理,提取某日访问百度次数最多的那个IP +类似问题: +a.怎么在海量数据中找出重复次数最多的一个? +b.服务器内存1G,有一个2G的文件,里面每行存着一个QQ号(5-10位数),怎么最快找出出现过最多次的QQ号。(10位数可以表示(不到)10亿个QQ号) + 分析 -2^32 = 42亿九千万。。 +一个IP可以用32bit表示,总共可以表示 2^32 = 42亿九千万。。个IP 假设一个IP一天内访问百度的次数不查过40亿次,可以用unsigned表示。用数组统计处每个IP地址出现的最大次数,就可以得到访问次数最大的IP地址 unsigned count[N],这个N=2^32=4G个IP地址 sizeof(count) = 4*N = 16G内存,原因超过32位机器所支持的4G内存大小。因此不能直接创建这个数组 @@ -39,12 +43,12 @@ unsigned count[N],这个N=2^32=4G个IP地址 sizeof(count) = 4*N = 16G内存, 1. 取模映射 。 IP%32 映射到32个小文件,把model相同的IP保存到同一个文件 2. 位运算映射。把IP的前5为作为作为区间编号,即 IP>>27 结果就是[0,31],把相同区间的IP保存到同一个文件 -上面的映射中,都不会出现同一个IP映射到不同小文件的情况 +上面的映射中,`都不会出现同一个IP映射到不同小文件的情况` 第二步 统计每个小文件中的最大值 -现在文件不同的IP数量达到内存承受的范文了,可以统计小文件中的IP次数了,使用常规的 hash_map(IP,count) 来 统计了 +现在文件不同的IP数量达到内存承受的范围了,可以统计小文件中的IP次数了,使用常规的 hash_map(IP,count) 来 统计了。可以分块读取来减少磁盘IO 第三步 排序 堆排序/快速排序/归并排序 @@ -94,9 +98,13 @@ int hash_function(const char *p) ### 文件中的内容排序并去重复 类似的题目有: -大量的URL字符串(电话号码),如何从中去除重复的,优化时间空间复杂度 +大量的URL字符串,如何从中去除重复的,优化时间空间复杂度 +对2亿条手机号码删除重复记录 +1) 如果文件太大,就分片 +2) 这里的问题是去除重复,分片后,小文件合并又是个麻烦事。 +3) 直接hash统计,假设不重复的url最多300万,采用hash存储需要的空间 300万*4 linux中的几个命令: @@ -113,7 +121,6 @@ sort -m 合并结果 - ### 在O(n lg k)时间内,将k个排序表合并成一个排序表,n为所有有序表中元素个数。 【解析】取前100 万个整数,构造成了一棵数组方式存储的具有小顶堆,然后接着依次取下一个整数,如果它大于最小元素亦即堆顶元素,则将其赋予堆顶元素,然后用Heapify调整整个堆,如此下去,则最后留在堆中的100万个整数即为所求 100万个数字。该方法可大大节约内存。 @@ -131,15 +138,74 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音 -2.一个文件,内含一千万行字符串,每个字符串在1K以内, -要求找出所有相反的串对,如abc和cba。 +一个文件,内含一千万行字符串,每个字符串在1K以内,要求找出所有相反的串对,如abc和cba。 +分析: +文件大小上限是:1000万*1K ~ 10GB。不可能内存操作 + +1) 设计hash函数 使得相反串得到相同的hash值 ? + + + + 一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数 +40亿*4 = 15GB, +4个字节表示的整数,总共有2^32个可能 +使用`位图法`来统计: +1)分配 2^29 X 2^3 = 512MB 的内存空间,每一个bit代表一个整数,全部初始化为0; +buffer[512x1024x1024] + +2) 读入一个数,把对应的bit位置为1. +如读入的是 312 , 将对应的bit置为1:312/8=39 312%8=0 ,写入位置是 第40个字节,0号bit + +3) 处理完40亿数据后,遍历500M内存,找到一个bit为0的位 +for(unsigned int i=0;i<0xffffffff,i++){ + if(!buffer){//为0则不包括这个整数 + + } +} + + +`位图法` 适用于大规模数据,通常用来判断某个数据存不存在 + +写入指定位: +bytepos = i/8 = i>>3 +bitpos = i%8 = i & 0x1F + +置为1:arr[bytepos] |= (1 << bitpos) +置为0:arr[bytepos] &= !(1<< bitpos) + +void setbit(int *bitmap,int i){ + bitmap[i>>3] |= (1 << (i&0x1F) ); +} + +读指定位: +getbit(int *bitmap,int i){ + return bitmap[i>>3] & ( 1 << (i&0x1F) ); +} + + + + 假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序。 +9位整数做多可表示10亿条不重复整数(无符号数) +9亿*4=3.4GB内存,一次读入内存是不可能了。 + +思路一: 位图法排序 +1) 计算需要内存: 9亿/8/1024/1024 < 120MB ,全部初始化为0 +2) 读取文件中的数据,将数据对应的bit位置1 +`分段读取` +3) 遍历整个bit,将bit为1的依次存入文件 + +思路二:? + + + + 给出一个文件,里面包含两个字段{url、size}, @@ -151,27 +217,25 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音 (说明:url数据量很大,100亿级以上) - - -有10个文件,每个文件1G, -每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。 -要求按照query的频度排序. -2.有一个很大很大的输入流,大到没有存储器可以将其存储下来,而且只输入一次,如何从这个输入流中随机取得m个记录 +有一个很大很大的输入流,大到没有存储器可以将其存储下来,而且只输入一次,如何从这个输入流中随机取得m个记录 -31、在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可。 +在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。只写出思路即可。 -32、一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数 +一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数 + + + +腾讯服务器每秒有2w个QQ号同时上线,找出5min内重新登入的qq号并打印出来。 -33、腾讯服务器每秒有2w个QQ号同时上线,找出5min内重新登入的qq号并打印出来。 @@ -191,7 +255,8 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音 -腾讯1.服务器内存1G,有一个2G的文件,里面每行存着一个QQ号(5-10位数),怎么最快找出出现过最多次的QQ号。(此题与稍后下文的第14题重复,思路参考请见下文第14题)。 + + @@ -233,6 +298,8 @@ s 求每对小文件中相同的url时,可以把其中一个小文件的url存 方 案2:如果允许有一定的错误率,可以使用Bloom filter,4G内存大概可以表示340亿bit。将其中一个文件中的url使用Bloom filter映射为这340亿bit,然后挨个读取另外一个文件的url,检查是否与Bloom filter,如果是,那么该url应该是共同的url(注意会有一定的错误率)。 + + 2. 有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。 方案1: @@ -251,13 +318,16 @@ s 对clip_image012[1]这10个文件进行归并排序(内排序与外排序相 与方案1类似,但在做完hash,分成多个文件后,可以交给多个文件来处理,采用分布式的架构来处理(比如MapReduce),最后再进行合并。 + + + 3. 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。 方案1:顺序读文件中,对于每个词x,取clip_image014,然后按照该值存到5000个小文件(记为clip_image016) 中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,知道分解得到的小文件的大小都不超过1M。对 每个小文件,统计每个文件中出现的词以及相应的频率(可以采用trie树/hash_map等),并取出出现频率最大的100个词(可以用含100个结点 的最小堆),并把100词及相应的频率存入文件,这样又得到了5000个文件。下一步就是把这5000个文件进行归并(类似与归并排序)的过程了。 -4. 海量日志数据,提取出某日访问百度次数最多的那个IP。 -方案1:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有clip_image018个 IP。同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进 行频率统计,然后再找出频率最大的几个)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。 + + 5. 在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。 @@ -265,6 +335,9 @@ s 对clip_image012[1]这10个文件进行归并排序(内排序与外排序相 方案2:也可采用上题类似的方法,进行划分小文件的方法。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。 + + + 6. 海量数据分布在100台电脑中,想个办法高校统计出这批数据的TOP10。 方案1: @@ -273,27 +346,37 @@ s 在每台电脑上求出TOP10,可以采用包含10个元素的堆完成(TO s 求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合起来,共1000个数据,再利用上面类似的方法求出TOP10就可以了。 -7. 怎么在海量数据中找出重复次数最多的一个? -方案1:先做hash,然后求模映射为小文件,求出每个小文件中重复次数最多的一个,并记录重复次数。然后找出上一步求出的数据中重复次数最多的一个就是所求(具体参考前面的题)。 + + + 8. 上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据。 方案1:上千万或上亿的数据,现在的机器的内存应该能存下。所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前N个出现次数最多的数据了,可以用第6题提到的堆机制完成。 -9. 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现? + + +1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现? 方案1:这题用trie树比较合适,hash_map也应该能行。 + + 10. 一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。 方 案1:这题是考虑时间效率。用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平准长度)。然后是找出出现最频繁的前10个 词,可以用堆来实现,前面的题中已经讲到了,时间复杂度是O(n*lg10)。所以总的时间复杂度,是O(n*le)与O(n*lg10)中较大的哪一 个。 + + + 11. 一个文本文件,找出前10个经常出现的词,但这次文件比较长,说是上亿行或十亿行,总之无法一次读入内存,问最优解。 方案1:首先根据用hash并求模,将文件分解为多个小文件,对于单个文件利用上题的方法求出每个文件件中10个最常出现的词。然后再进行归并处理,找出最终的10个最常出现的词。 + + 13. 寻找热门查询: 搜 索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较 高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询 串,要求使用的内存不能超过1G。 @@ -304,12 +387,17 @@ s 求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合 方案1:采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。 + + 14. 一共有N个机器,每个机器上有N个数。每个机器最多存O(N)个数并对它们操作。如何找到clip_image022个数中的中数? 方案1:先大体估计一下这些数的范围,比如这里假设这些数都是32位无符号整数(共有clip_image018[1]个)。我们把0到clip_image024的整数划分为N个范围段,每个段包含clip_image026个整数。比如,第一个段位0到clip_image028,第二段为clip_image026[1]到clip_image030,…,第N个段为clip_image032到clip_image024[1]。 然后,扫描每个机器上的N个数,把属于第一个区段的数放到第一个机器上,属于第二个区段的数放到第二个机器上,…,属于第N个区段的数放到第N个机器上。 注意这个过程每个机器上存储的数应该是O(N)的。下面我们依次统计每个机器上数的个数,一次累加,直到找到第k个机器,在该机器上累加的数大于或等于clip_image034,而在第k-1个机器上的累加数小于clip_image034[1],并把这个数记为x。那么我们要找的中位数在第k个机器中,排在第clip_image036位。然后我们对第k个机器的数排序,并找出第clip_image036[1]个数,即为所求的中位数。复杂度是clip_image038的。 方案2:先对每台机器上的数进行排序。排好序后,我们采用归并排序的思想,将这N个机器上的数归并起来得到最终的排序。找到第clip_image034[2]个便是所求。复杂度是clip_image040的。 + + + 15. 最大间隙问题 给定n个实数clip_image042,求着n个实数在实轴上向量2个数之间的最大差值,要求线性的时间算法。 @@ -324,6 +412,10 @@ s 将n个数放入n-1个桶中:将每个元素clip_image052分配到某个桶 s 最大间隙:除最大最小数据max和min以外的n-2个数据放入n-1个桶中,由抽屉原理可知至少有一个桶是空的,又因为每个桶的大小相同,所以最大间隙 不会在同一桶中出现,一定是某个桶的上界和气候某个桶的下界之间隙,且该量筒之间的桶(即便好在该连个便好之间的桶)一定是空桶。也就是说,最大间隙在桶 i的上界和桶j的下界之间产生clip_image056。一遍扫描即可完成。 + + + + 16. 将多个集合合并成没有交集的集合:给定一个字符串的集合,格式如:clip_image058。要求将其中交集不为空的集合合并,要求合并完成的集合之间无交集,例如上例应输出clip_image060。 (1) 请描述你解决这个问题的思路; @@ -334,6 +426,9 @@ s 最大间隙:除最大最小数据max和min以外的n-2个数据放入n-1个 方案1:采用并查集。首先所有的字符串都在单独的并查集中。然后依扫描每个集合,顺序合并将两个相邻元素合并。例如,对于clip_image062, 首先查看aaa和bbb是否在同一个并查集中,如果不在,那么把它们所在的并查集合并,然后再看bbb和ccc是否在同一个并查集中,如果不在,那么也把 它们所在的并查集合并。接下来再扫描其他的集合,当所有的集合都扫描完了,并查集代表的集合便是所求。复杂度应该是O(NlgN)的。改进的话,首先可以 记录每个节点的根结点,改进查询。合并的时候,可以把大的和小的进行合,这样也减少复杂度。 + + + 17. 最大子序列与最大子矩阵问题 数组的最大子序列问题:给定一个数组,其中元素有正,也有负,找出其中一个连续子序列,使和最大。 diff --git a/算法问题选编/链表.md b/算法问题选编/链表.md index 6756a68..2fcb589 100644 --- a/算法问题选编/链表.md +++ b/算法问题选编/链表.md @@ -5,13 +5,10 @@ 链表中是否有环 删除链表中的p节点,在p节点前面插入节点q, 要求O(1)复杂度 - 2个链表相交 2个链表合并 - - 判断俩个链表是否相交 给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。 为了简化问题,我们假设俩个链表均不带环。 @@ -107,7 +104,7 @@ p->next=NULL。此时,原单链表可以看作两条单链表,一条从head -62.找出链表的第一个公共结点。 +找出链表的第一个公共结点。 题目:两个单向链表,找出它们的第一个公共结点。 链表的结点定义为: @@ -117,51 +114,47 @@ struct ListNode ListNode* m_pNext; }; +分析: +第一个公共节点,也就是2个链表中的节点的m_pNext 指向的同一个节点。 +1) 先遍历2个链表,得到各自的长度,和差sub +2) 长链表先遍历sub个节点,然后2个节点一起遍历 +3) 第一次同时指向的同一个节点就是这个commonNode + 题目:从尾到头输出链表。输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下: - struct ListNode - { - int m_nKey; ListNode* m_pNext; - }; -分析:这是一道很有意思的面试题。 -该题以及它的变体经常出现在各大公司的面试、笔试题中。 +思路一: 辅助栈,需要一个栈空间 +思路二: 反转链表,然后遍历 +思路三: 递归实现,将printf语句放在递归调用后面。果然妙极。。 - - -从尾到头打印链表 - -60.在O(1)时间内删除链表结点。 +在O(1)时间内删除链表结点。 题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下: - struct ListNode - { - int m_nKey; ListNode* m_pNext; }; 函数的声明如下: - void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted); -分析:这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。 +思路: +保存下一个节点的值tmp,删除下一个节点,当前节点=tmp -36、有双向循环链表结点定义为: +有双向循环链表结点定义为: struct node { int data; @@ -174,7 +167,8 @@ struct node -78.链表和数组的区别在哪里? + +链表和数组的区别在哪里? 分析:主要在基本概念上的理解。 但是最好能考虑的全面一点,现在公司招人的竞争可能就在细节上产生, @@ -182,14 +176,3 @@ struct node -  ★说说各种股票分类算法的优点和缺点。 -  ★用一种算法来颠倒一个链接表的顺序。现在在不用递归式的情况下做一遍。 -  ★用一种算法在一个循环的链接表里插入一个节点,但不得穿越链接表。 -  ★用一种算法整理一个数组。你为什么选择这种方法? -   -  ★假设你有一个用1001个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗? -  ★不用乘法或加法增加8倍。现在用同样的方法增加7倍。 - - - -