实习招聘时碰到的编程题,最后都是卡在动态规划。看过一些动态规划的帖子,前面概念性的东西全靠个人理解了,这里不再赘述。
什么时候用动态规划?(就做笔试题而言,看题目比较难,不知道从何开始的时候,一般就是要用动态规划做了。)当然,应该要看一些问题特征之类的······
sample1:背包问题(01背包、完全背包、多重背包)有N件物品和一个容量为V的背包,第i件物品的所占容量为c[i],价值为w[i],问哪些物品放入背包可以使总和不超过背包容量,且价值总和最大。问题主要在最大价值总和,至于是选哪些物品,在之后重新判断打印输出即可。以下分析都是动态规划法求最大总和部分
01背包(每件物品只能拿一次):面对每件物品,只有拿和不拿的状态。用二维数组dp[i][j]表示面对第i件物品,其背包容量剩下j时,能获得的最大价值。那当然,二维数组的右下角的数为能获得的最大价值dp[N][V]。
对于每一个dp[i][j],首先分为背包剩余容量是否放的下第i件物品的情况:j<c[i],拿不了这件物品,dp[i][j]=dp[i-1][j];j>=c[i],放得下这件物品,则开始考虑价值,比较拿和不拿的两种价值,取最大的价值,dp[i][j]=max{dp[i-1][j],dp[i-1][j-c[i]]+w[i]}。
完全背包(每件物品无限次使用):与01背包的不同唯一在于,第二层循环不同,j的取值是c[i]到V
多重背包(第i件物品有对应的数量):可转化为01背包,添加一层循环,设置物品的数量dp[i][j]=max{dp[i-1][j],dp[i-1][j-k*c[i]]+k*w[i]}
sample2:最长公共子序列/串
最长公共子序列:dp[i][j]表示遍历到序列A的第i个字符和序列B的第j个字符的公共序列的最长长度。对应俩元素相等时,dp[i][j]=dp[i-1][j-1]+1;不相等时,dp[i][j]=max{dp[i-1][j],dp[i][j-1]}。最优解为dp[lenA][lenB]。
最长公共子串:与前者不同的是这个需要连续的子串,前者不需要连续。当对应俩元素不同的时候,dp[i][j]=0。同时还需要一个整数来记录长度,用于比较历史result和当前的dp长度,最大值更新result,遍历全部完成的result即为最优解。
解决这类问题,用实际例子分析一次会比较清晰。
sample3:最长回文字串(华为笔试题1)
普通解法和动态规划解法。做华为笔试的时候还没开始看动态规划,用的是普通解法,通过率100%。