s647. 回文子串
class Solution {public:int countSubstrings(string s) {// dp[i][j] s[i,j]是否是回文子串int n = s.size(), res = 0;vector<vector<bool>> dp(n, vector<bool>(n, false));for (int i=0; i<n; i++){for (int j=0; j<=i; j++){// 只有一个字符 || 去除两边的子串是回文if (s[i] == s[j] && (i-j<2 || dp[j+1][i-1])){dp[j][i] = true;res++;}}}return res;}};
516. 最长回文子序列
这里的遍历顺序,完全是根据状态转移方程来设定的,保证用到时,已经计算出来了即可。
class Solution {public:int longestPalindromeSubseq(string s) {int n = s.size();vector<vector<int>> dp(n, vector<int>(n, 0));for (int i=0; i<n; i++){dp[i][i] = 1;for (int j=i-1; j>=0; j--){if (s[j] == s[i])dp[j][i] = max(dp[j+1][i-1] + 2, dp[j][i]);elsedp[j][i] = max(dp[j+1][i], dp[j][i-1]);}}return dp[0][n-1];}};
416. 分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
class Solution {public:bool canPartition(vector<int>& nums) {/*1. 先求数组的总和suma. sum奇数, 返回falseb. sum偶数i. 将问题转化为01背包问题,然后进行求解target = sum/2*/int sum = accumulate(nums.begin(), nums.end(), 0);if (sum & 1) return false;int n = nums.size(), m = sum / 2;vector<vector<int>> f(n+1, vector<int>(m+1, 0));for (int i=1; i<=n; i++){for (int j=1; j<=m; j++){int wv = nums[i-1];if (j >= wv)f[i][j] = max(f[i-1][j], f[i-1][j-wv] + wv);elsef[i][j] = f[i-1][j];}}if (f[n][m] == m) return true;return false;}};
空间优化
class Solution {public:bool canPartition(vector<int>& nums) {int sum = accumulate(nums.begin(), nums.end(), 0);if (sum & 1) return false;int n = nums.size(), m = sum / 2;vector<int> f(m+1, 0);for (int i=1; i<=n; i++){int wv = nums[i-1];for (int j=m; j>=wv; j--)f[j] = max (f[j], f[j-wv] + wv);}if (f[m] == m) return true;return false;}};
