一、问题
问题1:给几个数字,输出排列的种树;或者是八皇后问题
问题2:给定一字符串,字符串里有*,*可以换成0或者1,输出各种可能情况。(比如说,字符串是01*78aljdou*a,可以变成01178aljdou1a、01078aljdou1a、01078aljdou0a、01078aljdou0a四种情况。
问题3:输入为字符串,是一串数字,输出各种可能的ip地址(leetcode上Restore IP Addresses)
问题4:在leetcode上一道题,decode ways。 'A' -> 1 'B' -> 2 ... 'Z' -> 26
问题5:给一个数字,如果是奇数,可以加一和减一操作;如果是偶数,可以除以2。我们最终要让这个数变为一,最少的步数是多少?
问题6:给定一串字符串,再给一个字典,将字符串分解为字典中存在的单词,并将各种情况打印出来。
二、dfs
面对上面这些题时,你仔细比较一下,都是输出各种可能情况,可以看做一种排列问题。怎么用dfs解决这种问题呢? 首先就用问题2举个例子,当访问到*的时候,我需要解决当前问题,可以把*换成0和1两种情况,剩下的问题又成了独立的问题,再递归调用处理剩下的问题。稍微用朴素的语言归纳一下,可以先枚举当前情况,再递归解决后面各种出现的情况.最后写一个伪代码吧,来说明这种思路。
dfs(整个问题){
取当前一部分,枚举当前情况,并解决
dfs(剩下的问题)
}
三、dp
在解决上面的第3、4个问题时,你会发现,有很多重复计算,所以说要保留重复计算的部分,我可以把它分解为一个个子问题,怎么把一个子问题编程再大一点的问题呢?这就要寻找一种大问题与小问题之间的递推关系。下面就用第四个问题来举例,分析一下怎么得到这个递归关系。以问题3为例,首先,从头到尾扫这个String,从第一位到dp[i]这一位组成的String,有多少种解码组合。( 保存重复运算子问题)
可以有两种情况:( 分解子问题)1)只解析当前字符,有dp[i-1]种;2)解析i-1和i时,那么dp[i-2]种
那么递归关系得到dp[i]=dp[i-1]+dp[i-2];(求解最优子结构,这里当然没有通过比较最大最小得到最优,很自然的得到递推)(形式有点类似斐波那契数列,http://blog.csdn.net/qomoman/article/details/38351041)
同样,在问题5中,同样有类似的递推关系,我们可以分析子问题。3.1 dp总结
我觉得可以写成伪代码,如下分解子问题,子问题求解,并且保存子问题的解,防止重复运算
从众多子问题中,并选取最优的子问题解,得到大问题与子问题的递推关系
从伪代码和上面分析问题的方法中,我们也可以有比较重要的三点:
1)分解子问题,怎么划分子问题?其实是一个分治的思想
2)保存子问题的解,其实就是以空间换时间,防止重复求解
3)最优子结构,比较所有种可能性,得到全局最优