您的位置:首页 > 职场人生

几个dp面试题分析

2014-11-02 20:34 162 查看
1.最长递增子序列

给出一个数组,找出最少元素,使得将其删除后,剩下的元素是递增有序的。

分析:问题等价于寻找最长递增子序列。很明显是动态规划问题。dp问题的关键是找到一个公式或方法,使得可以由此产生我们需要的解。对于这个问题直接考虑情况很多,很容易束手无策。不妨假设已经找到一个最长递增子序列,然后研究该序列的规律。比如对于数组:1 6 3 2 5 8 7 9.一个最长递增子序列是1 3 5 7 9.我们取中间的5,最长递增子序列就是以5结尾的最长递增子序列,加上后面以5开头的最长递增子序列。设dp[i]是以i结尾的最长递增子序列,那么递推关系就是

dp[i]=max{dp[i],dp[j]+1},其中j<i,同时,A[j]<=A[i];

初始化时每个元素构成一个序列。

dp问题分析是关键,分析出来代码就容易了。。。

2.最长回文子串

输入一字符串S,找出其最长回文子串。

分析:这里指的是连续的串,用二维数组dp[i][j]标记a[i]到a[j]是否是回文串。dp[i][j]=dp[i+1][j-1],(a[i]==a[j]);false;(a[i]!=a[j])

代码如下:

class Main
{
public static String longestPalindrome(String s){
int n = s.length(), longestBegin=0, maxLen=-1;
boolean dp[][] = new boolean

;
for(int i=0; i<n; i++) dp[i][i] = true;

for(int i=0; i<n-1; i++){
if(s.charAt(i) == s.charAt(i+1)){
dp[i][i+1] = true;
longestBegin = i;
maxLen = 2;
}
}
for(int i=n-3; i>=0; i--){
for(int j=i+2; j < n; j++){
if(s.charAt(i) == s.charAt(j) && dp[i+1][j-1]){
dp[i][j] = true;
longestBegin = i;
maxLen = j-i+1;
}
}
}

return s.substring(longestBegin,longestBegin+maxLen);
}
public static void main(String[] args)throws IOException
{
out.println(longestPalindrome("deabcbafg"));
}
}


3.最少回文分割数

给出一个字符串s,将s进行分割,使得每个子串均为回文,求最少回文分割数。

分析:例如输入s="aab",最少回文分割数为1,即"aa","b"。

用dp[i]记录从s[i]到字符串末尾的分割数,用isPa[i][j]标志从s[i]到s[j]是否是回文,dp[i]=min{dp[i],dp[j+1]+1};初始化时,认为每个字符都是一个回文,所以dp[i]=len-i+1。isPa[i][j]同上一题。

class Main
{
public static int minPalincut(String s){
int len = s.length();
int dp[] = new int[len+1];
boolean isPa[][] = new boolean[len][len];
for(int i=0;i<=len;i++) dp[i] = len-i-1;
for(int i=len-1;i>=0;i--){
for(int j=i;j<len;j++){
if(s.charAt(i)==s.charAt(j)&&(j-i<2||isPa[i+1][j-1])){
isPa[i][j] = true;
dp[i] = Math.min(dp[i],dp[j+1]+1);
}
}
}
return dp[0];
}
public static void main(String[] args)throws IOException
{
out.println(minPalincut("deabcbafg"));
}
}


4.给出两个数组A和B,两个数组的大小分别是m和n,其中m<n。现要求将(n-m)个0插入A,使得A*B的值最小,求其最小乘积。

分析:1.自底向上 设dp[i][j]表示A中前i个元素与B中前j个元素的乘积最小值。

当i=0,j=0时,dp[0][0] =A[i]*A[j] = A[0]*B[0];

当i=0,0<j<n时,dp[i][j] = min{A[i]*B[j],dp[i][j-1]};

当0<i<j<n时,dp[i][j] = min{A[i]*B[j]+dp[i-1][j-1],dp[i][j-1]};

2.自顶向下:根据关系dp[i][j] = min{dp[i][j-1],A[i]*B[j]+dp[i-1][j-1]}写递归,中间加个记忆化搜索。

5.给出一个数组A,求其连续子数组最大和。

分析:dp[i]表示以i结尾的最大连续子数组和,那么递推公式就是dp[i]=max(dp[i-1]+A[i],A[i]);其实这里只要求最大和,不用数组也可以,直接使用一个变量代替。curMAX = max(curMAX+A[i],A[i]);

6.给出一个二维mxn矩阵,含有非负整数。找出一条路径从左上角到右下角,使之经过元素之和最小。假定只能向右或向下移动。

分析:这个比较简单。组合数学里常见的题目。根据题意,一个格子要么是从正上方的格子下来的,要么是从左边的格子过来的,所以dp[i][j] = min(dp[i-1][j],dp[i][j-1])+A[i][j];(其中dp[i][j]代表到达(i,j)时的最小和).

7.输入一个三角形,找出一条从顶部到底部的最小路径和。只能向下移动相邻的点。

分析:跟上一题非常像。最简单的方法是把三角形倒过来,这样到下一行的每一个元素的最小和就是它上一行相邻的两个里面较小的与其之和。递推关系:dp[i][j] = min(dp[i-1][j-1],dp[i-1][j])+A[i][j];

8.给只有A到Z的字符串加密,加密规则是A-1,B-2。。。Z-26。现有一个已经加密的密文,求其解密方法数。

分析:主要是两位数的解密方法可能会有两种情况,比如26,可以是Z,也可以是BF。递推关系还是比较容易想到的,设dp[i]表示到第i个数字时的解密方法数,那么对于第i个数字,它要么自己单独是一个字符,要么与前面一个数字合起来作为一个字符(要求<=26)。所以递推关系就是:dp[i]=0,s[i]='0';dp[i-1]+dp[i-2],与前面的数字合起来<=26;dp[i-1],其他情况。当然也可以倒序扫描数组。

9.输入两个字符串S和T,求出T在S中的子序列个数。一个字符串的子序列是从该串删除多个字符(也可能不删除)而且保留字符相对顺序不变的子串。

分析:前面的大都是在一个串中操作,现在变成了两个串,难度也提高了。分析方法与前面的是一样的,从最优子结构入手,设dp[i][j]是S中从开始到i,T中从开始到j的子序列个数。那么如果S中第i个字符与T中第j个字符相同,就有两种情况,一种是T中前j个元素在S中前i-1个元素中匹配,一种是不匹配,所以有dp[i][j] = dp[i-1][j]+dp[i-1][j-1];如果S中第i个字符与T中第j个字符不同,则有dp[i][j] = dp[i-1][j];

10.输入两个单词word1和word2,求出从word1转换为word2的最少步骤。每个转换操作算一步。转换操作限定于插入一个字符,删除一个字符和替换一个字符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: