4.03
出现次数超过一半的数字 题目描述 题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。 分析与解法 一个数组中有很多数,现在我们要找出其中那个出现次数超过总数一半的数字,怎么找呢?大凡当我们碰到某一个杂乱无序的东西时,我们人的内心本质期望是希望把它梳理成有序的。所以,我们得分两种情况来讨论,无序和有序。 解法一 如果无序,那么我们是不是可以先把数组中所有这些数字先进行排序(至于排序方法可选取最常用的快速排序)。排完序后,直接遍历,在遍历整个数组的同时统计每个数字的出现次数,然后把那个出现次数超过一半的数字直接输出,题目便解答完成了。总的时间复杂度为O(nlogn +...
5
本章导读 学习一个算法,可分为3个步骤:首先了解算法本身解决什么问题,然后学习它的解决策略,最后了解某些相似算法之间的联系。例如图算法中, 广搜是一层一层往外遍历,寻找最短路径,其策略是采取队列的方法。 最小生成树是最小代价连接所有点,其策略是贪心,比如Prim的策略是贪心+权重队列。 Dijkstra是寻找单源最短路径,其策略是贪心+非负权重队列。 Floyd是多结点对的最短路径,其策略是动态规划。 而贪心和动态规划是有联系的,贪心是“最优子结构+局部最优”,动态规划是“最优独立重叠子结构+全局最优”。一句话理解动态规划,则是枚举所有状态,然后剪枝,寻找最优状态,同时将每一次求解子问题的结果保存在一张“表格”中,以后再遇到重叠的子问题,从表格中保存的状态中查找(俗称记忆化搜索)。
5.01
最大连续乘积子串 题目描述 给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积30.58=12是最大的,而且是连续的。 分析与解法 此最大乘积连续子串与最大乘积子序列不同,请勿混淆,前者子串要求连续,后者子序列不要求连续。也就是说,最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence,LCS)是: 子串(Substring)是串的一个连续的部分, 子序列(Subsequence)则是从不改变序列的顺序,而从序列中去掉任意的元素而获得的新序列; 更简略地说,前者(子串)的字符的位置必须连续,后者(子序列LCS)则不必。比如字符串“ acdfg ”同“ akdfc ”的最长公共子串为“ df ”,而它们的最长公共子序列LCS是“ adf...
字符串编辑距离
字符串编辑距离 题目描述 给定一个源串和目标串,能够对源串进行如下操作: 在给定位置上插入一个字符 替换任意字符 删除任意字符 写一个程序,返回最小操作数,使得对源串进行这些操作后等于目标串,源串和目标串的长度都小于2000。 分析与解法 此题常见的思路是动态规划,假如令dp[i][j] 表示源串S[0…i] 和目标串T[0…j] 的最短编辑距离,其边界:dp[0][j] = j,dp[i][0] = i,那么我们可以得出状态转移方程: dp[i][j] =min{ dp[i-1][j] + 1 , S[i]不在T[0…j]中 dp[i-1][j-1] + 1/0 , S[i]在T[j] dp[i][j-1] + 1 , S[i]在T[0…j-1]中 } 接下来,咱们重点解释下上述3个式子的含义 关于dp[i-1][j] + 1, s.t....
5.03
格子取数问题 题目描述 有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右,一共走两次(即从左上角走到右下角走两趟),把所有经过的格子的数加起来,求最大值SUM,且两次如果经过同一个格子,则最后总和SUM中该格子的计数只加一次。 分析与解法 初看到此题,因为要让两次走下来的路径总和最大,读者可能最初想到的思路可能是让每一次的路径都是最优的,即不顾全局,只看局部,让第一次和第二次的路径都是最优。 但问题马上就来了,虽然这一算法保证了连续的两次走法都是最优的,但却不能保证总体最优,相应的反例也不难给出,请看下图: 上图中,图一是原始图,那么我们有以下两种走法可供我们选择: 如果按照上面的局部贪优走法,那么第一次势必会如图二那样走,导致的结果是第二次要么取到2,要么取到3, 但若不按照上面的局部贪优走法,那么第一次可以如图三那样走,从而第二次走的时候能取到2 4...
5.04
交替字符串 题目描述 输入三个字符串s1、s2和s3,判断第三个字符串s3是否由前两个字符串s1和s2交错而成,即不改变s1和s2中各个字符原有的相对顺序,例如当s1 = “aabcc”,s2 = “dbbca”,s3 =...
5.06
最长递增子序列 题目描述 给定一个长度为N的数组a0,a1,a2…,an-1,找出一个最长的单调递增子序列(注:递增的意思是对于任意的i<j,都满足ai<aj,此外子序列的意思是不要求连续,顺序不乱即可)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4。 分析与解法 解法一:转换为最长公共子序列问题 比如原数组为 A{5, 6, 7, 1, 2, 8}, 当我们对这个数组进行排序后,排序后的数组为: A‘{1, 2, 5, 6, 7,...
5.1
本章动态规划的习题 1.子序列个数 子序列的定义:对于一个序列a=a[1],a[2],…a[n],则非空序列a’=a[p1],a[p2]…a[pm]为a的一个子序列 其中1<=p1<p2<…<pm<=n。 例如:4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。 对于给出序列a,有些子序列可能是相同的,这里只算做1个。 要求输出a的不同子序列的数量。 2.数塔取数问题 一个高度为N的由正整数组成的三角形,从上走到下,求经过的数字和的最大值。 每次只能走到下一层相邻的数上,例如从第3层的6向下走,只能走到第4层的2或9上。 5 8 4 3 6 9 7 2 9 5 例子中的最优方案是:5 + 8 + 6 + 9 = 28。 3.最长公共子序列 什么是最长公共子序列呢?好比一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列。 举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5...
6
...
6.01
关联式容器 一般来说,STL容器分为: 序列式容器(vector/list/deque/stack/queue/heap),和关联式容器。 其中,关联式容器又分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表),这些容器均以RB-tree(red-black tree,...