《剑指offer》笔记-第2章(3)

来源:互联网 发布:网络教育报考哪个学校 编辑:程序博客网 时间:2024/05/02 02:09

2.4.3 回溯法

回溯法:从解决问题的每一步的所有可能选项里系统地选择出一个可行方案。

适合由多个步骤组成的问题,每个步骤都有多个选项,所有选项可以形象地用树状结构表示。

一个节点的状态不满足约束条件,回溯到它的上一个节点;如果上一个节点所有可能的选项都已经尝试过,并且都不满足约束条件,则再次回溯到上一个节点;如果所有选项都已尝试过,仍不能满足约束条件,则问题无解。

面试题12:矩阵中的路径

设计一个函数,判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一格可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了某一格,那么该路径不能再次进入该格子。

测试用例:

1.    在多行多列的矩阵中存在/不存在路径;

2.    矩阵只有一行/一列;矩阵和路径中的所有字母都是相同的;

3.    Null指针

分析:

1.    路径可被看成给一个栈;

2.    当矩阵中定位了前n个字符的位置后,在与第n个字符对应的格子周围都没有找到第n+1个字符时,回溯到第n-1个字符,重新定位第n个字符

3.    需要一格布尔值矩阵,表示路径是否已经进入了每个格子

 

2.4.4 动态规划与贪婪算法

可以用动态规划求解的问题的特点:

1.    求一个问题的最优解(通常是最大最小值)

2.    整体的最优解是依赖各个子问题的最优解

3.    该问题能分解成若干个子问题,并且子问题之间还有重叠的更小的子问题

4.    由于子问题在分解大问题的过程中重复出现,为避免重复求解子问题,可以从下往上的顺序先计算小问题的最优解并存储下来(从上往下分析问题,从下往上解决问题)

贪婪算法:用贪婪算法解决问题时,每一步都做出一个贪婪的选择,但需要用数学的方法证明贪婪选择是正确的

面试题14 剪绳子

一根长度为n的绳子,把绳子剪成m段(m、n都是整数),每段绳子的长度记为k[0]、k[1]……k[m],求出k[0]*k[1]*……*k[m],最大的乘积是多少

测试用例:

1.    绳子长度大于5

2.    绳子长度为0,1,2,3,4

动态规划解决问题:

1.    f(n)为把长度为n的绳子剪成若干段后个长度成绩的最大值。则f(n)=max(f(i)*f(n-i))

2.    从上到下的递归,会有很多重复的子问题

3.    从下到上顺序计算更简单,计算f(2) f(3)……直到f(n)

贪婪算法解决问题:

1.    根据数学规律,按照一下策略剪绳子得到的乘积最大

2.    当n>=5时,尽可能多地剪出长度为3的绳子

3.    当剩下的绳子长度为4时,把绳子剪成两端2和2

灵活运用动态规划需要具备从上到下分析问题、从下到上解决问题的能力;

灵活运用贪婪算法需要扎实的数学功底

2.4.5 位运算

位运算的种类:

与、或、异或(模2加)

左移(m<<n表示把m左移n位,最左边n位丢弃,最右边补n个0)、

右移(同左移;如果数字是无符号数值,则用0填补最左边的n位,如果数字是一个有符号数值,则用数字的符号位填补最左边的n位)

面试题15:二进制中1的个数

实现一个函数,输入一个整数,输出该数二进制表示中1的个数

测试用例:

1.    正数(边界1、0x7FFFFFFF)

2.    负数(边界0x80000000 0xFFFFFFFF)

3.    0

分析:

1.    该数与1做与运算,可以判断该数最低位是不是1

2.    将该数右移一位可以判断次低位是不是1,以此类推

3.    2的问题是,如果是负数,右移后左边填充1,最终数字变为0xFFFFFFF进入死循环

4.    那么可以不移动该数,将1左移一位变成0x00000010,与该数进行与运算,判断次低位是不是1,以此类推

另一种解法:

5.    另一种方法,一个整数减去1,就把该整数最右边的1变成0,如果它的右边还有0,则所有右边的0都变成1,而它左边的所有为保持不变

6.    把一个整数和它减去1的结果做与运算,相当于把最右边的1变成0(很多二进制问题都可用这个思路解决)

7.    一个整数的二进制能进行多少次这样的操作,就有多少个1