思路:node
子序列说明能够不连续。正则表达式
对于任意字符串,若是其头尾相同,则其回文子序列的长度是其去头去尾字符串回文子序列长度+2,若是头尾不一样,则是去头或去尾字符串回文子序列中长的那个。数组
状态转移方程:
使用数组dpi表示子串i-j的最长回文子序列,则函数
if(i==j) dp[i][j] = 1; if(i>j) dp[i][j] = 0; if(i<j && s[i]==s[j]) dp[i][j] = dp[i+1][j-1]+2; if(i<J && s[i]!=s[j]) dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
代码:code
int longestPalindromeSubseq(string s) { int ss = s.size(); int dp[ss][ss]; memset(dp,0,sizeof(dp)); for(int i=ss-1;i>=0;--i){ dp[i][i] = 1; for(int j=i+1;j<ss;++j){ if(s[i]==s[j]) dp[i][j] = dp[i+1][j-1]+2; else dp[i][j] = max(dp[i+1][j],dp[i][j-1]); } } return dp[0][ss-1]; }
思路:
对于这种题,咱们须要遍历全部可能的游戏状态,并使用动态规划避免重复遍历。游戏状态能够表示成当前剩下的可选数列表。对于某个状态,有两种转移,一种是咱们从剩下数中能够选择一个数直接获胜,另外一个是咱们选择一个数后,在通过若干回合后对方会输。也就是两个递归的状态。递归
代码:游戏
unordered_map<int,bool> mp; bool canIWin(int m, int d) { if(m>=d) return true; if(m*(m+1)/2 < d) return false; return dp(m,d,0); } bool dp(int m,int d,int state){ if(mp.count(state)) return mp[state]; for(int i=0;i<m;++i){ if(((1<<i) & state)==0){ if(i+1>=d || !dp(m,d-i-1,state | (1<<i))){ return mp[state] = true; } } } return mp[state] = false; }
思路:字符串
对于某个n,咱们能够分别把1-n做为根,求出其结构数,而后加起来就是总数。string
代码:it
int numTrees(int n) { if(n<2) return 1; int res[n+1] = {1,1}; for(int i=2;i<=n;++i){ for(int j=0;j<i;++j){ res[i] += res[j]*res[i-j-1]; } } return res[n]; }
二叉树的结构:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
思路:
对于一个1-n中的i,咱们能够根据其i-1时的二叉树构建出新的二叉树,分为两种状况:
新节点做为根节点,那么i-1的全部二叉树分别做为其左子树就好
新节点不是根节点,那么对于i-1的二叉树,只要对于找寻最大节点路径上的每一个节点,把新节点插入进去就获得全部的情形
语言描述可能不太清楚,能够看代码
代码:
TreeNode * clone(TreeNode *root){ if(root==nullptr) return nullptr; TreeNode *node = new TreeNode(root->val); node->left = clone(root->left); node->right = clone(root->right); return node; } vector<TreeNode*> generateTrees(int n) { vector<TreeNode*> res; if(n==0) return res; res.push_back(nullptr); for(int i=1;i<=n;++i){//ith new node vector<TreeNode *> temp; for(int j=0;j<res.size();++j){//jth old trees of i-1 TreeNode * newtree = new TreeNode(i); newtree->left = res[j]; temp.push_back(clone(newtree)); if(res[j]!=nullptr){ TreeNode *tnode = res[j]; while(tnode->right!=nullptr){ newtree->left = tnode->right; tnode->right = newtree; temp.push_back(clone(res[j])); tnode->right = newtree->left; tnode = tnode->right; } tnode->right = newtree; newtree->left = nullptr; temp.push_back(clone(res[j])); } } res = std::move(temp); } return res; }
思路:
很显然,状态转移方程是
dp[i][j] = grid[i][j] + min(dp[i+1][j],dp[i][j+1]);
根据这个方程,咱们能够直接写出代码以下:
int minPathSum(vector<vector<int>>& grid) { if(grid.size()==0) return 0; int m = grid.size()-1; int n = grid[0].size()-1; int dp[m+1][n+1]; memset(dp,0,sizeof dp); dp[m][n] = grid[m][n]; for(int j=n-1;j>=0;--j){ dp[m][j] = grid[m][j] + dp[m][j+1]; } for(int i=m-1;i>=0;--i){ for(int j=n;j>=0;--j){ dp[i][j] = grid[i][j] + min(dp[i+1][j],dp[i][j+1]); } } return dp[0][0]; }
可是这样作的空间复杂度有O(N^2),咱们还能够作的更好,咱们注意到,在每一次状态转移时,咱们只用到了两行,一行是当前要修改的行,另外一行是修改行的下面一行,因此咱们能够只用到O(N)的空间来解决:
int minPathSum(vector<vector<int>>& grid) { if(grid.size()==0) return 0; int m = grid.size()-1; int n = grid[0].size()-1; int dp[2][n+1]; memset(dp,0,sizeof dp); dp[0][n] = grid[m][n]; for(int j=n-1;j>=0;--j){ dp[0][j] = grid[m][j] + dp[0][j+1]; } int cur = 1,old = 0; for(int i=m-1;i>=0;--i){ for(int j=n;j>=0;--j){ dp[cur][j] = grid[i][j] + min(dp[old][j],dp[cur][j+1]); } swap(old,cur); } return dp[old][0]; }
思路
首先设一个bool型dp数组,dpi表示s[0:i-1]和p[0:j-1]是否匹配。
显而易见的是dpi = i==0?true:false;
而dp0取决于pattern中是否都是a的形式,dp0确定是false,i>1时,dp0 = p[j-1]==''&&dp0==true;
对于通常状况,咱们要注意的是p的最后一个字符是否是'*',由于'.'没有讨论的必要,它能够匹配任何字符。
若是p[j-1]不是'*',那么dpi仅仅取决于p[j-1]是否能和s[i-1]匹配,而且dpi-1须要是能匹配空字符串的格式;
若是p[j-1]是'',又能够分红两种状况,一种是p最后的x不匹配字符,另外一种是x*匹配一个字符,而且dpi-1是true的。
状态转移方程
dp[i][0] = i==0?true:false; dp[0][i] = i==1?false:(p[i-1]=='*' && dp[0][i-2]); dp[i][j] = p[j-1]=='*'?(dp[i][j-2] || (s[i-1]==p[j-2] || p[j-2]=='.') && dp[i-1][j]):(dp[i][j] = (s[i-1]==p[j-1] || p[j-1]=='.') && dp[i-1][j-1]);
代码
bool isMatch(string s, string p) { int m = s.size(),n = p.size(); bool dp[m+1][n+1]; memset(dp,0,sizeof dp); dp[0][0] = true; for(int i=2;i<=n;++i){ dp[0][i] = p[i-1]=='*' && dp[0][i-2]; } for(int i=1;i<=m;++i){ for(int j=1;j<=n;++j){ if(p[j-1]=='*'){ dp[i][j] = dp[i][j-2] || (s[i-1]==p[j-2] || p[j-2]=='.') && dp[i-1][j]; }else{ dp[i][j] = (s[i-1]==p[j-1] || p[j-1]=='.') && dp[i-1][j-1]; } } } return dp[m][n]; }