最長迴文子串
注意子串需要判斷兩端之間的子串是否是迴文串
class Solution {
public:
string longestPalindrome(string s) {
if(s.size() <=1) return s;
if(s.size() == 2 && s[0]==s[1]) return s;
if(s.size()==3 &&s[0]==s[2]) return s;
int m=s.size();
bool dp[m][m];
for(int i=0;i<m;++i){
for(int j=0;j<m;++j){
dp[i][j] = false;
}
}
int max_len =0;
int max_s_start =0;
for(int i=0;i<m;++i){
for(int j=i;j>=0;--j){
if(i==j) {
dp[j][i]=true;
}else if(s[i] == s[j]){
if(j+1 == i) dp[j][i] =true;
else if(j+1<=i-1 && dp[j+1][i-1]) dp[j][i]=true;
else dp[j][i]=false;
}else{
dp[j][i]=false;
}
if(dp[j][i]){
if(i-j+1 > max_len){
max_len =i-j+1;
max_s_start =j;
}
}
}
}
return s.substr(max_s_start,max_len);
}
};
516 最長迴文子序列
dp[i][j]表示s[i]開頭 s[j]結尾的子串
從而通過判斷s[i]與s[j]是否相等,找到dp[i][j] 與dp[i+1][j-1]關係或與dp[j+1][i],dp[j][i-1]關係
class Solution {
public:
int longestPalindromeSubseq(string s) {
if(s.size()<=1) return s.size();
int dp[s.size()][s.size()];
for(int i=0;i<s.size();++i){
for(int j=i;j>=0;--j){
if(i==j){
dp[j][i]=1;
}else{
//兩端字符相同,從裏側子串推導,注意j+1==i的情況
if(s[i]==s[j]){
if(j+1<=i-1) dp[j][i]=dp[j+1][i-1]+2;
else{
dp[j][i]=2;
}
}else{
//兩端字符不同,則各取一端,取最大值
dp[j][i]=max(dp[j+1][i],dp[j][i-1]);
}
}
}
}
return dp[0][s.size()-1];
}
};
312 打氣球
此題的解題關鍵是每個氣球得分是與向鄰兩側氣球分數有關。所以可以假設氣球i爲最後一個射破氣球。再將氣球i分割爲左右兩個子區間L,R。因此依賴於L R的解。
class Solution {
public:
//<1>核心要點:
//想到把某個氣球作爲最後一個被射擊的,從而可以得到一個狀態。但是該氣球把整個序列化爲左右子區間
//此時應意識到應該以區間作爲迭代元素,從小區間逐漸迭代到大區間,從而在以氣球劃分子區間時,可將子區間結果作爲已知量。
int maxCoins(vector<int>& nums) {
if(nums.size()==0) return 0;
if(nums.size()== 1)return nums[0];
int N=nums.size();
//兩側加1,作爲邊界
vector<int>temp={1};
for(auto i:nums){
temp.push_back(i);
}
temp.push_back(1);
//dp[i][j]代表只射擊區間[i,j]的最大score
int dp[N+1][N+1];
//依次掃描長度爲1 2 ...N的區間
for(int len=1;len<=N;++len){
//對每種區間長度,生成區間的首尾元素
for(int start=1;start<=N;++start){
int end = start+len-1;
if(end>N) break;
//區間只有一個元素,直接射破
if(start == end){
dp[start][end] = temp[start-1]*temp[start]*temp[end+1];
}else{
//依次假設區間某個元素爲最後一個被射擊,先求其左右子區間
//最終得到當前區間最大值
dp[start][end]=0;
for(int last = start;last<=end;++last){
int left_sub_range_score =0;
int right_sub_range_score =0;
if(last-1>=start) left_sub_range_score=dp[start][last-1];
if(last+1<=end) right_sub_range_score=dp[last+1][end];
//射爆最後一個氣球時,由於左右子區間已經被射掉,因此乘以當前區間兩邊外側的第一個元素
int last_burst_score=temp[start-1]*temp[last]*temp[end+1];
dp[start][end] = max(dp[start][end],left_sub_range_score+last_burst_score+right_sub_range_score);
}
}
}
}
return dp[1][N];
}
};