思路: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]; }