研究生学过DP,当时觉得还挺简单的,就是从初始状态开始,找到推导公式一步步往下推嘛。但实际刷题时发现DP还是很难的,有时候想不到或者理不清推导的逻辑。今天笔试了一家大公司,两道编程题全是dp问题,而且leetcode上全有但是当时觉得挺难所以跳过了,现在还是要还的。
1.通配符wildcard
借用leetcode上的题目描述:
Implement wildcard pattern matching with support for '?' and ''.
'?' Matches any single character.
'' Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char s, const char p)
Some examples:
isMatch("aa","a") ? false
isMatch("aa","aa") ? true
isMatch("aaa","aa") ? false
isMatch("aa", "") ? true
isMatch("aa", "a") ? true
isMatch("ab", "?") ? true
isMatch("aab", "ca*b") ? false
这时候就可以用一个二维数组储存dp结果,dp[i][j]表示s的前i位和p的前j位的字符串的匹配结果。
初始化dp[i][0]和dp[0][j]。
dp[i][j] = true当出现以下之一情况:
1.dp[i-1][j] == true && p[j-1] == '*',因为通配符最后一位是所以s随便加一个没关系啦;
2.dp[i][j-1] == true && p[j-1] == '*',因为加的是这个无所谓所以还是成立啦;
3.dp[i-1][j-1] == true && s[i-1] == p[j-1],通配符和字符串加个一样的字符还是成立啦。
4.dp[i-1][j-1] == true && p[j-1] == '*'或'?'。
其他情况dp[i][j]就为false啦。
public static boolean isMatch(String s, String p) {
int sLength = s.length();
int pLength = p.length();
char[] sChar = s.toCharArray();
char[] pChar = p.toCharArray();
boolean[][] dp = new boolean[sLength + 1][pLength + 1];
dp[0][0] = true;
for(int i = 1; i < sLength + 1; i++){
dp[i][0] = false;
}
for(int j = 1; j < pLength + 1; j++){
if(dp[0][j-1] && pChar[j-1] == '*') dp[0][j] = true;
else dp[0][j] = false;
}
for(int i = 1; i < sLength + 1; i++){
for(int j = 1; j < pLength + 1; j++){
if((pChar[j-1] == '*' && (dp[i-1][j] || dp[i][j-1])) ||
(dp[i-1][j-1] && (pChar[j-1] == '*' || pChar[j-1] == '?' || pChar[j-1] == sChar[i-1]))){
dp[i][j] = true;
}else{
dp[i][j] = false;
}
}
return dp[sLength][pLength];
}
2.最长上升子序列Longest Increasing Subsequence
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
建立dp数组,dp[i]储存的是以a[i]为结尾的最长上升子序列的长度。
初始dp[0] = 0。
dp[i] = 1 + Max {dp[j]} s.t. j < i && a[j] < a[i]。
注意最后求得的是dp中的最大值,因为最大值不一定是以最后一个数结尾的最大上升子序列哦。
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0;
int[] dp = new int[nums.length];
dp[0] = 1;
for(int i = 1; i < nums.length; i++){
dp[i] = 1;
for(int j = 0; j < i; j++){
if(dp[j] >= dp[i] && nums[i] > nums[j]){
dp[i] = dp[j] + 1;
}
}
}
int res = 1;
for(int i = 1; i < nums.length; i++){
if(res < dp[i]){
res = dp[i];
}
}
return res;
}