一刷leetcode——dp

5. Longest Palindromic Substring

题意:返回字符串的最长回文子串

我的思路:dp,http://blog.csdn.net/kangroger/article/details/37742639

我的代码:

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n <= 1) return s;
        vectorint> > dp(n, vector<int>(n));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                if (i == j || (abs(i-j) == 1 && s[i] == s[j])) dp[i][j] = 1;
                else dp[i][j] = 0;
            }
        string ans = s.substr(0, 1);
        for (int l = 2; l <= n; l++) {
            for (int i = 0; i < n-l+1; i++) {
                int j = i+l-1;
                dp[i][j] = (s[i] == s[j]) ? dp[i+1][j-1] : 0;
                if (dp[i][j] == 1 && l > ans.size()) ans = s.substr(i, l);
            }
        }
        return ans;
    }
};
View Code

solution解法:

class Solution {
public:
    string longestPalindrome(string s) {
        if (s.empty()) return "";
        if (s.size() == 1) return s;
        int min_start = 0, max_len = 1;
        for (int i = 0; i < s.size();) {
          if (s.size() - i <= max_len / 2) break;
          int j = i, k = i;
          while (k < s.size()-1 && s[k+1] == s[k]) ++k; // Skip duplicate characters.
          i = k+1;
          while (k < s.size()-1 && j > 0 && s[k + 1] == s[j - 1]) { ++k; --j; } // Expand.
          int new_len = k - j + 1;
          if (new_len > max_len) { min_start = j; max_len = new_len; }
        }
        return s.substr(min_start, max_len);
    }
};
View Code

Manacher算法:http://www.cnblogs.com/grandyang/p/4475985.html

class Solution {
public:
    string longestPalindrome(string s) {
        string t = "$#";
        for (int i = 0; i < s.size(); ++i) {
            t += s[i];
            t += "#";
        }
        vector<int> p(t.size(), 0);
        int mx = 0, id = 0, resLen = 0, resCenter = 0;
        for (int i = 1; i < t.size(); ++i) {
            p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
            while (t[i + p[i]] == t[i - p[i]]) ++p[i];
            if (mx < i + p[i]) {
                mx = i + p[i];
                id = i;
            }
            if (resLen < p[i]) {
                resLen = p[i];
                resCenter = i;
            }
        }
        return s.substr((resCenter - resLen) / 2, resLen - 1);
    }
};
View Code

10. Regular Expression Matching

题意:问b串能否匹配成a串,其中b串里的 ‘.’ 可以表示任意单一字符, ‘*’ 可以表示0个或任意多个他前边的字符

我的思路:dp,dp[i][j]表示a串的前i个字符与b串的前j个字符能否匹配,很垃圾的看了几眼discuss。。

我的代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size(), n = p.size();
        vectorint> > dp(m+1, vector<int>(n+1, 0));
        dp[0][0] = 1;
        for (int i = 0; i < n; i++)
            dp[0][i+1] = i > 0 && dp[0][i-1] && p[i] == '*';
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (s[i] == p[j] || p[j] == '.') dp[i+1][j+1] = dp[i][j];
                else if (p[j] == '*') {
                    dp[i+1][j+1] = dp[i+1][j-1] || (s[i] == p[j-1] || p[j-1] == '.') && dp[i][j+1];
                } else dp[i+1][j+1] = 0;
            }
        }
        return dp[m][n];
    }
};
View Code

32. Longest Valid Parentheses

题意:给定一组小括号序列,求括号合法的最长连续子串的长度

思路:

1)栈解法

class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> sk;
        int n = s.size(), ans = 0, start = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] == '(') sk.push(i);
            else {
                if (sk.empty()) start = i+1;
                else {
                    sk.pop();
                    ans = sk.empty() ? max(ans, i-start+1) : max(ans, i-sk.top());
                }
            }
        }
        return ans;
    }
};
View Code

2)DP解法

class Solution {
public:
    int longestValidParentheses(string s) {
        int n = s.size(), ans = 0;
        vector<int> dp(n, 0);
        for (int i = n-2; i >= 0; i--) {
            if (s[i] == '(') {
                int tail = i+dp[i+1]+1;
                if (tail < n && s[tail] == ')') {
                    dp[i] = dp[i+1]+2;
                    if (tail+1 < n) dp[i] += dp[tail+1];
                }
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};
View Code

44. Wildcard Matching

题意:匹配串,第10题稍作改动即可

我的代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size(), n = p.size();
        vectorint> > dp(m+1, vector<int>(n+1, 0));
        dp[0][0] = 1;
        for (int i = 0; i < n; i++)
            dp[0][i+1] = dp[0][i] && p[i] == '*';
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (s[i] == p[j] || p[j] == '?') dp[i+1][j+1] = dp[i][j];
                else if (p[j] == '*') {
                    dp[i+1][j+1] = dp[i+1][j] || dp[i][j+1];
                } else dp[i+1][j+1] = 0;
            }
        }
        return dp[m][n];
    }
};
View Code

solution解法:

class Solution {
public:
    bool isMatch(string s, string p) {
        int  slen = s.size(), plen = p.size(), i, j, iStar=-1, jStar=-1;

        for(i=0,j=0 ; ij)
        {
            if(p[j]=='*')
            { //meet a new '*', update traceback i/j info
                iStar = i;
                jStar = j;
                --i;
            }
            else
            { 
                if(p[j]!=s[i] && p[j]!='?')
                {  // mismatch happens
                    if(iStar >=0)
                    { // met a '*' before, then do traceback
                        i = iStar++;
                        j = jStar;
                    }
                    else return false; // otherwise fail
                }
            }
        }
        while(p[j]=='*') ++j;
        return j==plen;
    }
};
View Code

85. Maximal Rectangle

题意:给定一个01二维矩阵,输出最大矩形1面积

思路:http://blog.csdn.net/makuiyu/article/details/44857479

我的代码:

解法一

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.push_back(-1);
        int i = 0, n = heights.size(), ans = 0;
        stack<int> loc;
        while (i < n) {
            if (loc.empty() || heights[loc.top()] <= heights[i]) {
                loc.push(i++);
            } else {
                int tmp = loc.top();
                loc.pop();
                int l = loc.empty() ? 0 : loc.top()+1;
                ans = max(ans, heights[tmp]*(i-l));
            }
        }
        return ans;
    }
    int maximalRectangle(vectorchar>>& matrix) {
        if (matrix.size() == 0) return 0;
        int ans = 0;
        int m = matrix.size(), n = matrix[0].size();
        vector<int> h(n, 0);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '0') h[j] = 0;
                else h[j]++;
            }
            ans = max(ans, largestRectangleArea(h));
        }
        return ans;
    }
};
View Code

解法二

class Solution {
public:
    int maximalRectangle(vectorchar>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) return 0;
        int ans = 0, m = matrix.size(), n = matrix[0].size();
        vector<int> h(n, 0), l(n, 0), r(n, n);
        for (int i = 0; i < m; i++) {
            int cur_l = 0, cur_r = n; //左闭右开
            for (int j = n-1; j >= 0; j--) {
                r[j] = matrix[i][j] == '1' ? min(r[j], cur_r) : n;
                cur_r = matrix[i][j] == '1' ? cur_r : j;
            }
            for (int j = 0; j < n; j++) {
                h[j] = matrix[i][j] == '1' ? h[j]+1 : 0;
                l[j] = matrix[i][j] == '1' ? max(l[j], cur_l) : 0;
                cur_l = matrix[i][j] == '1' ? cur_l : j+1;
                ans = max(ans, h[j]*(r[j]-l[j]));
            }
        }
        return ans;
    }
};
View Code

87. Scramble String

题意:问两个字符串能否由写成二叉树后翻转节点得到

我的思路:http://blog.csdn.net/makuiyu/article/details/44926439

我的代码:

class Solution {
public:
    bool isScramble(string s1, string s2) {
        if (s1.size() != s2.size()) return 0;
        int n = s1.size();
        vectorint> > > dp(n, vectorint> >(n, vector<int>(n+1, 0)));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                dp[i][j][1] = s1[i] == s2[j];
        for (int l = 2; l <= n; l++)
            for (int i = 0; i <= n-l; i++)
                for (int j = 0; j <= n-l; j++)
                    for (int k = 1; k < l; k++)
                        dp[i][j][l] = dp[i][j][l] || dp[i+k][j+k][l-k] && dp[i][j][k] || dp[i][j+l-k][k] && dp[i+k][j][l-k];
        return dp[0][0][n];
    }
};
View Code

91. Decode Ways

题意:将A~Z编码成1~26,给定一串数字,求有多少种解码方式

我的思路:简单dp,1*或者21~26可以由隔一个来,其他的只能由前一个来(整十特例支能友隔一个来)

我的代码:

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        if (n == 0 || s[0] == '0') return 0;
        vector<int> dp(n+1);
        dp[0] = dp[1] = 1;
        for (int i = 1; i < n; i++) {
            if (s[i] != '0') dp[i+1] = dp[i];
            if (s[i-1] == '1' || s[i-1] == '2' && s[i] <= '6') dp[i+1] += dp[i-1]; 
        }
        return dp[n];
    }
};
View Code

优化:dp没必要开那么大,只留前两个值就可以

96. Unique Binary Search Trees

题意:求整数1~n能形成的二叉查找树的数目

我的思路:递归实现的分治,左右子树的数目相乘求和

我的代码:

class Solution {
public:
    int dfs(int n) {
        int ans = 0;
        if (n <= 1) return 1;
        for (int i = 0; i < n/2; i++) ans += dfs(i)*dfs(n-1-i)*2;
        if (n%2) ans += pow(dfs(n/2), 2);
        return ans;
    }
    int numTrees(int n) {
        return dfs(n);
    }
};
View Code

九章最优解:dp,两重循环

class Solution {
public:
    /**
     * @paramn n: An integer
     * @return: An integer
     */
    int numTrees(int n) {
        // write your code here
        int f[n + 1];
        memset(f, 0, sizeof(int) * (n + 1));
        f[0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < i; j++) {
                f[i] += f[j] * f[i - 1 - j];
            }
        }
        return f[n];
    }
};
View Code

97. Interleaving String

题意:判断一个字符串能不能由两个字符串按照他们自己的顺序,每次挑取两个串中的一个字符来构造出来。、

我的思路:比较简单的一个dp,把两个字符串作为横纵坐标看成棋盘,则目标就是判断能否从左上角走到右下角

我的代码:

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int m = s1.size(), n = s2.size(), k = s3.size();
        if (k != m+n) return 0;
        if (m == 0) return s2 == s3;
        if (n == 0) return s1 == s3;
        vectorint> > dp(m+1, vector<int>(n+1, 0));
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) dp[0][i] = dp[0][i-1] && (s3[i-1] == s2[i-1]);
        for (int i = 1; i <= m; i++) dp[i][0] = dp[i-1][0] && (s3[i-1] == s1[i-1]);
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                dp[i][j] = dp[i][j-1] && (s3[i+j-1] == s2[j-1]) || dp[i-1][j] && (s3[i+j-1] == s1[i-1]);
        return dp[m][n];
    }
};
View Code

120. Triangle

题意:给定一个三角形二维数组,输出从上到下最小和,路径只能往左下、右下最近的走

我的思路:基础dp,大白书上第一道dp题

我的代码:

class Solution {
public:
    int minimumTotal(vectorint>>& triangle) {
        for (int i = triangle.size()-2; i >= 0; i--)
            for (int j = 0; j <= i; j++)
                triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1]);
        return triangle[0][0];
    }
};
View Code

九章最优解:他是从上往下加和,不如从下往上走的好

class Solution {
public:
    /**
     * @param triangle: a list of lists of integers.
     * @return: An integer, minimum path sum.
     */
    int minimumTotal(vectorint> > &triangle) {
        // write your code here
        if (triangle.size() == 0)
            return 0;
            
        vector<int> f(triangle[triangle.size()-1].size());
        
        f[0] = triangle[0][0];
        for(int i = 1; i < triangle.size(); i++)
            for(int j = triangle[i].size() - 1; j >= 0; j--)
                if (j == 0)
                    f[j] = f[j] + triangle[i][j];
                else if (j == triangle[i].size() - 1)
                    f[j] = f[j-1] + triangle[i][j];
                else
                    f[j] = min(f[j-1], f[j]) + triangle[i][j];
                    
        int ret = INT_MAX;
        for(int i = 0; i < f.size(); i++)
            ret = min(ret, f[i]);
        return ret; 
    }
};
View Code

121. Best Time to Buy and Sell Stock

题意:给定一个数组表示股票价格,限制一天买一天卖(可以是同一天),输出最大盈利

我的思路:维护一个dp值表示某天以前的最小值,在按天更新差值,巨水dp

我的代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() == 0) return 0;
        int ans = 0, dp = prices[0];
        for (int i = 1; i < prices.size(); i++) {
            dp = min(dp, prices[i]);
            ans = max(ans, prices[i]-dp);
        }
        return ans;
    }
};
View Code

九章最优解:一样

class Solution {
public:
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(vector<int> &prices) {
        // write your code here
        if (prices.empty()) return 0;
        int i=prices.size()-1, ans=0, maxp=prices[i];
        for (--i; i>=0; --i){
            ans=max(ans, maxp-prices[i]);
            maxp=max(maxp, prices[i]);
        }
        return ans;
    }
};
View Code

123. Best Time to Buy and Sell Stock III

题意:卖股票,最多两次交易,求最大收益

我的思路:两种解法:http://blog.csdn.net/u012501459/article/details/46514309

我的代码:

1)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n <= 1) return 0;
        vector<int> dp1(n, 0), dp2(n, 0);
        int ans, minn = prices[0], maxn = prices[n-1];
        for (int i = 1; i < n; i++) {
            minn = min(minn, prices[i]);
            dp1[i] = max(dp1[i-1], prices[i]-minn);
        }
        ans = dp1[n-1];
        for (int i = n-2; i >= 0; i--) {
            maxn = max(maxn, prices[i]);
            dp2[i] = max(dp2[i+1], maxn-prices[i]);
            ans = max(ans, dp1[i]+dp2[i+1]);
        }
        return ans;
    }
};
View Code

 2)solution

132. Palindrome Partitioning II

题意:给定一个字符串,最少劫几次使得各子串都是回文串

我的思路:

1)dp,pal[i][j]表示s[i]~s[j]是否是回文串,dp[i]表示s[i]~s[n-1]的最小cut数,当j==n-1且s[i~j]是回文串时,dp[i] = 0,否则当s[i~j]是回文串时,更新dp[i]为min(dp[i], dp[j+1]+1)

我的代码:

class Solution {
public:
    int minCut(string s) {
        if (s.size() == 0) return 0;
        int n = s.size();
        vectorbool> > pal(n, vector<bool>(n, 0));
        vector<int> dp(n);
        for (int i = n-1; i >= 0; i--) {
            dp[i] = n-1-i;
            for (int j = i; j < n; j++) {
                if (s[i] == s[j] && (j-i < 2 || pal[i+1][j-1])) {
                    pal[i][j] = 1;
                    if (j == n-1) dp[i] = 0;
                    else dp[i] = min(dp[i], dp[j+1]+1);
                }
            }
        }
        return dp[0];
    }
};
View Code

2)solution,绝了,从一点往外扩来判断回文

代码:

class Solution {
public:
    int minCut(string s) {
        int n = s.size();
        vector<int> cut(n+1, 0);  // number of cuts for the first k characters
        for (int i = 0; i <= n; i++) cut[i] = i-1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; i-j >= 0 && i+j < n && s[i-j]==s[i+j] ; j++) // odd length palindrome
                cut[i+j+1] = min(cut[i+j+1],1+cut[i-j]);

            for (int j = 1; i-j+1 >= 0 && i+j < n && s[i-j+1] == s[i+j]; j++) // even length palindrome
                cut[i+j+1] = min(cut[i+j+1],1+cut[i-j+1]);
        }
        return cut[n];
    }
};
View Code

139. Word Break

题意:给定一个字典,判断串s能否由字典里的词组成、

我的思路:dp

我的代码:

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        int n = s.size();
        vector<int> dp(n+1, 0);
        dp[0] = 1;
        for (int i = 0; i < n; i++)
            for (int j = 1; j <= n+1-i; j++)
                dp[i+j] = dp[i+j] | ((find(wordDict.begin(), wordDict.end(), s.substr(i, j)) != wordDict.end()) ? dp[i] : 0);
        return dp[n];
    }
};
View Code

140. Word Break II

题意:将一个字符串分成各个单词相连,给定字典,输出所有情况

我的思路:dfs+记忆化搜素,map记录下已经找过的情况

我的代码:

class Solution {
public:
    unordered_map<string, vector<string>> m;
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        if (m.find(s) != m.end()) return m[s];
        vector<string> ans;
        if (find(wordDict.begin(), wordDict.end(), s) != wordDict.end()) ans.push_back(s);
        for (int l = 1; l < s.size(); l++) {
            string tmp = s.substr(0, l);
            if (find(wordDict.begin(), wordDict.end(), tmp) != wordDict.end()) {
                vector<string> gg, hehe = wordBreak(s.substr(l, s.size()-l), wordDict);
                for (int i = 0; i < hehe.size(); i++)
                    gg.push_back(tmp+' '+hehe[i]);
                ans.insert(ans.end(),gg.begin(), gg.end());
            }
        }
        m[s] = ans;
        return ans;
    }
};
View Code

152. Maximum Product Subarray

题意:求数组的最大子串积

我的思路:保存两个dp变量分别为以nums[i]结尾的最大正数积和最小负数积,分别更新这两个变量,返回最大的最大正数积即可

我的代码:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int ans = nums[0], maxn = nums[0] > 0 ? nums[0] : 0, minn = nums[0] < 0 ? nums[0] : 0;
        for (int i = 1; i < nums.size(); i++) {
            int tmp1 = nums[i] > 0 ? maxn*nums[i] : minn*nums[i];
            int tmp2 = nums[i] > 0 ? minn*nums[i] : maxn*nums[i];
            maxn = max(tmp1, nums[i]);
            minn = min(tmp2, nums[i]);
            ans = max(ans, maxn);
        }
        return ans;
    }
};
View Code

九章最优解:思路一样,他两个dp变量是两个数组,没有必要

class Solution {
public:
    /**
     * @param nums: a vector of integers
     * @return: an integer
     */
    int maxProduct(vector<int>& nums) {
        // write your code here
        vector<int> f, g;
        f.push_back(nums[0]);
        g.push_back(nums[0]);
        for (int i=1; ii) {
            f.push_back(max(max(f[i-1]*nums[i], g[i-1]*nums[i]), nums[i]));
            g.push_back(min(min(f[i-1]*nums[i], g[i-1]*nums[i]), nums[i]));        
        }
        int m = f[0];
        for (int i=1; i max(m, f[i]);
        return m;
    }
};
View Code

174. Dungeon Game

题意:给定一个二维数组,每个数表示到这个位置要减去或者加上的值,求从左上到右下初始值最少是多少?只能往右或往下走,过程中值不能小于等于0

我的思路:dp,dp[i][j]表示这个位置最少需要多少值,从右下往左上推

我的代码:

class Solution {
public:
    int calculateMinimumHP(vectorint>>& dungeon) {
        int m = dungeon.size(), n = dungeon[0].size();
        vectorint>> dp(m+1, vector<int>(n+1, 0x7fffffff));
        dp[m][n-1] = dp[m-1][n] = 1;
        for (int i = m-1; i >= 0; i--)
            for (int j = n-1; j >= 0; j--)
                dp[i][j] = (min(dp[i][j+1], dp[i+1][j]) > dungeon[i][j] ? min(dp[i][j+1], dp[i+1][j])-dungeon[i][j] : 1);
        return dp[0][0];
    }
};
View Code

188. Best Time to Buy and Sell Stock IV

题意:给定一组股票价格,输出最多k次交易约束下的最大收益

我的思路:123题解法二

我的代码:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        k = min(k, (int)prices.size());
        if (k == 0) return 0;
        vector<int> buy(k, 0x80000000);
        vector<int> sell(k, 0);
        for (int i = 0; i < prices.size(); i++) {
            for (int j = k-1; j >= 0; j--) {
                sell[j] = max(sell[j], buy[j]+prices[i]);
                buy[j] = (j > 0 ? max(buy[j], sell[j-1]-prices[i]) : max(buy[j], -prices[i]));
            }
        }
        return sell[k-1];
    }
};
View Code

198. House Robber

题意:给定一个数组取数,不能取连续的两个,求取出的最大和

我的思路:简单dp,dp[i] = max(dp[i-2]+nums[i], dp[i-1])

我的代码:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() > 1) nums[1] = max(nums[0], nums[1]);
        for (int i = 2; i < nums.size(); i++)
            nums[i] = max(nums[i-2]+nums[i], nums[i-1]);
        return nums[nums.size()-1];
    }
};
View Code

九章最优解:思路一样,写法不同

class Solution {
public:
    /**
     * @param A: An array of non-negative integers.
     * return: The maximum amount of money you can rob tonight
     */
    long long houseRobber(vector<int> A) {
        // write your code here
        long long result = 0;
        long long f = 0, g = 0, f1 = 0, g1 = 0;
        int len = A.size();
        for (int i = 0; i < len; ++i) {
            f1 = g + A[i];
            g1 = max(f, g);
            g = g1, f = f1;        
        }
        return max(g, f);
    }
};
View Code

213. House Robber II

题意:数组是环形的,其余跟上题一样

我的思路:两遍上题的dp,一种是nums[0]~nums[n-2],一种是nums[1]~nums[n-1],两种分别代表了有无第一间房,两者取大的

我的代码:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        vector<int> nums2(nums);
        if (nums.size() > 1) nums[1] = max(nums[0], nums[1]);
        for (int i = 2; i < nums.size()-1; i++)
            nums[i] = max(nums[i-2]+nums[i], nums[i-1]);
        nums2[0] = 0;
        for (int i = 2; i < nums.size(); i++)
            nums2[i] = max(nums2[i-2]+nums2[i], nums2[i-1]);
        return max(nums[nums.size()-2], nums2[nums.size()-1]);
    }
};
View Code

九章最优解:思路是一样的,写法不一样

class Solution {
public:
    /**
     * @param nums: An array of non-negative integers.
     * return: The maximum amount of money you can rob tonight
     */
    int houseRobber2(vector<int>& nums) {
        // write your code here
        int n = nums.size();
        if (n == 0)
            return 0;
        if (n == 1)
            return nums[0];

        vector<int> dp(n);
        
        dp[0] = 0;
        dp[1] = nums[1];
        for (int i = 2; i < n; ++i)
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

        int answer = dp[n - 1];

        dp[0] = nums[0];
        dp[1] = max(dp[0], nums[1]);
        for (int i = 2; i < n; ++i)
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

        return max(dp[n - 2], answer);
    }
};
View Code

221. Maximal Square

题意:给定01二维数组,输出最大的1构成的正方形面积

我的思路:85题法一改一点就可以用,但是时间不好

我的代码:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.push_back(-1);
        int i = 0, n = heights.size(), ans = 0;
        stack<int> loc;
        while (i < n) {
            if (loc.empty() || heights[loc.top()] <= heights[i]) {
                loc.push(i++);
            } else {
                int tmp = loc.top();
                loc.pop();
                int l = loc.empty() ? 0 : loc.top()+1;
                ans = max(ans, min(heights[tmp], (i-l))*min(heights[tmp], (i-l)));
            }
        }
        return ans;
    }
    int maximalSquare(vectorchar>>& matrix) {
        if (matrix.size() == 0) return 0;
        int ans = 0;
        int m = matrix.size(), n = matrix[0].size();
        vector<int> h(n, 0);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == '0') h[j] = 0;
                else h[j]++;
            }
            ans = max(ans, largestRectangleArea(h));
        }
        return ans;
    }
};
View Code

 solution解法:

  1. P[0][j] = matrix[0][j] (topmost row);
  2. P[i][0] = matrix[i][0] (leftmost column);
  3. For i > 0 and j > 0: if matrix[i][j] = 0P[i][j] = 0; if matrix[i][j] = 1P[i][j] = min(P[i - 1][j], P[i][j - 1], P[i - 1][j - 1]) + 1
class Solution {
public:
    int maximalSquare(vectorchar>>& matrix) {
        if (matrix.empty()) return 0;
        int m = matrix.size(), n = matrix[0].size(), pre, ans = 0;
        vector<int> dp(n+1, 0);
        for (int i = 0; i < m; i++) {
            pre = 0;
            for (int j = 1; j <= n; j++) {
                int tmp = dp[j];
                if (matrix[i][j-1] == '1') {
                    dp[j] = min(dp[j], min(dp[j-1], pre))+1;
                    ans = max(ans, dp[j]);
                } else
                    dp[j] = 0;
                pre = tmp;
            }
        }
        return ans*ans;
     }
};
View Code

279. Perfect Squares

题意:输出n最少可由几个平方数求和得到

我的思路:dp递推

我的代码:

class Solution {
public:
    int numSquares(int n) {
        vector<int> num(n+1, 0);
        for (int i = 0; i <= n; i++)
            if (i == 0 || num[i] > 0)
                for (int j = 1; i+j*j <= n; j++)
                    num[i+j*j] = num[i+j*j] == 0 ? num[i]+1 : min(num[i+j*j], num[i]+1);
        return num[n];
    }
};
View Code

九章最优解:三种解法,我的是最平常的。。还看不明白。。

// version 1
class Solution {
public:
    /**
     * @param n a positive integer
     * @return an integer
     */
    int numSquares(int n) {
        // Write your code here
        vector<int> dp{ 0 };
        dp.resize(n + 1, INT_MAX);
        for (int i = 1, k; (k = i * i) <= n; ++i)
            for (int j = k; j <= n; ++j)
                if (dp[j] > dp[j - k] + 1)
                    dp[j] = dp[j - k] + 1;
        return dp[n];
    }
};


// version 2 Math
class Solution {
public:
    /**
     * @param n a positive integer
     * @return an integer
     */
    int numSquares(int n) {
        // Write your code here
        int ub = sqrt(n);
        for (int a = 0; a <= ub; ++a) {
            for (int b = a; b <= ub; ++b) {
            int c = sqrt(n - a * a - b * b);
                if (a * a + b * b + c * c == n)
                    return !!a + !!b + !!c;
            }
        }
        return 4;
    }
};

// version 3 Math II
class Solution {
public:
    /**
     * @param n a positive integer
     * @return an integer
     */
    int numSquares(int n) {
        // Write your code here
        while (n % 4 == 0)
            n /= 4;
        if (n % 8 == 7)
            return 4;
        for (int i = 0; i * i <= n; ++i) {
            int j = sqrt(n - i * i);
            if (i * i + j * j == n)
                return !!i + !!j;
        }
        return 3;
    }
};
View Code

300. Longest Increasing Subsequence

题意:最长上升子序列裸题

我的思路:大白书P62,掌握O(nlogn)的写法

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;
        vector<int> g(n+1, 0x7fffffff);
        vector<int> d(n);
        for (int i = 0; i < n; i++) {
            int k = lower_bound(g.begin()+1, g.end(), nums[i])-g.begin();
            d[i] = k;
            g[k] = nums[i];
        }
        for (int i = 1; i < n; i++) d[i] = max(d[i], d[i-1]);
        return d[n-1];
    }
};
View Code

九章最优解:O(n^2)的次优解

303. Range Sum Query - Immutable

题意:输出数组[i,j]元素之和

我的思路:大水题

我的代码:

class NumArray {
public:
    vector<int> sum;
    NumArray(vector<int> nums) {
        sum.resize(nums.size()+1, 0);
        for (int i = 1; i <= nums.size(); i++) sum[i] = sum[i-1]+nums[i-1];
    }
    
    int sumRange(int i, int j) {
        return sum[j+1]-sum[i];
    }
};
View Code

304. Range Sum Query 2D - Immutable

题意:给定一个矩阵和左上右下两个点下标,求小矩阵中的值之和

我的思路:sum[i][j]表示第i行[0, j]元素之和

我的代码:

class NumMatrix {
public:
    vectorint>> sum;
    NumMatrix(vectorint>> matrix) {
        int m = matrix.size();
        if (m > 0) {
            int n = matrix[0].size();
            sum.resize(m);
            for (int i = 0; i < m; i++) sum[i].resize(n);
            for (int i = 0; i < m; i++) 
                for (int j = 0; j < n; j++)
                    sum[i][j] = (j == 0 ? matrix[i][j] : matrix[i][j]+sum[i][j-1]);
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        int ans = 0;
        for (int i = row1; i <= row2; i++)
            ans += (col1 == 0 ? this->sum[i][col2] : this->sum[i][col2]-this->sum[i][col1-1]);
        return ans;
    }
};

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix obj = new NumMatrix(matrix);
 * int param_1 = obj.sumRegion(row1,col1,row2,col2);
 */
View Code

九章最优解:dp[i][j]表示元素[i][j]左上角的元素之和

class NumMatrix {
private:
    vectorint>> dp;

public:
    NumMatrix(vectorint>> matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return;
        }
        int n = matrix.size();
        int m = matrix[0].size();
        
        dp.resize(n + 1, vector<int>(m + 1, 0));
        for (int r = 0; r < n; r++) {
            for (int c = 0; c < m; c++) {
                dp[r + 1][c + 1] = dp[r + 1][c] + dp[r][c + 1] + matrix[r][c] - dp[r][c];
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        return dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1];
    }
};
View Code

309. Best Time to Buy and Sell Stock with Cooldown

题意:任意次股票买卖,有冷却期(卖出后至少一天不可以买入),求最大收益

思路:https://www.cnblogs.com/grandyang/p/4997417.html

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int buy = 0x80000000, buy_pre = 0, sell = 0, sell_pre = 0;
        for (int i = 0; i < prices.size(); i++) {
            buy_pre = buy;
            buy = max(sell_pre-prices[i], buy_pre);
            sell_pre = sell;
            sell = max(buy_pre+prices[i], sell_pre);
        }
        return sell;
    }
};
View Code

312. Burst Balloons

题意:每次打破一个气球,获得他的值与左右两个数的乘积,依次打破所有气球(顺序自定,打破之后它左右两个变为相邻),求获得的最大值

思路:discuss第一个,dp[i][j]为从i到j的气球打完获得的最大值,着眼于最后打破的那个,dp[left][right] = max(dp[left][right], nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right]);

我的代码:

class Solution {
public:
    int maxCoins(vector<int>& nums) {
        nums.insert(nums.begin(), 1);
        nums.insert(nums.end(), 1);
        int n = nums.size();
        vectorint>> dp(n, vector<int>(n, 0));
        for (int k = 2; k < n; k++)
            for (int i = 0; i < n-k; i++)
                for (int j = i+1; j < i+k; j++)
                    dp[i][i+k] = max(dp[i][i+k], dp[i][j]+dp[j][i+k]+nums[i]*nums[j]*nums[i+k]);
        return dp[0][n-1];
    }
};
View Code

322. Coin Change

题意:给定一组硬币面值和一个总价,求组成总价最少需要多少硬币,不能组成返回-1

我的思路:简单dp

我的代码:

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> num(amount+1, amount+1);
        num[0] = 0;
        for (int i = 1; i <= amount; i++)
            for (int j = 0; j < coins.size(); j++)
                if (i-coins[j] >= 0) num[i] = min(num[i], num[i-coins[j]]+1);
        return num[amount] > amount ? -1 : num[amount];
    }
};
View Code

solution解法:我的是解法三

      https://leetcode.com/problems/coin-change/solution/

334. Increasing Triplet Subsequence

题意:判断是否有长度为3的上升子序列(可以不挨着)

我的思路:根据题300求上升子串长度,大于等于3时返回1

我的代码:

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;
        vector<int> g(n+1, 0x7fffffff);
        vector<int> d(n);
        for (int i = 0; i < n; i++) {
            int k = lower_bound(g.begin()+1, g.end(), nums[i])-g.begin();
            d[i] = k;
            if (d[i] >= 3) return 1;
            g[k] = nums[i];
        }
        //for (int i = 1; i < n; i++) d[i] = max(d[i], d[i-1]);
        return 0;
    }
};
View Code

九章最优解:不用那么麻烦,记录上升三个数的前两个,扫一遍,大于谁更新谁,同时大于两个即返回1

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        if (nums.size() < 3)
            return false;
        vector<int> ans(2, INT_MAX);
        
        for (int now : nums) {
            if (now <= ans[0]) {
                ans[0] = now;
            } else if (now <= ans[1]) {
                ans[1] = now;
            } else {
                return true;
            }
        }
        return false;
    }
};
View Code

343. Integer Break

题意:将正一个整数拆分为至少两个正整数之和,使他们的和最大

我的思路:dp,但是当一个数拆分为另两个数a, b时,既可能是a,b本身,也可能是dp[a],dp[b],共四种情况

我的代码:

class Solution {
public:
    int integerBreak(int n) {
        vector<int> dp(n+1, 0);
        dp[1] = 1;
        for (int i = 2; i <= n; i++){
            for (int j = 1; j <= i/2; j++) {
                dp[i] = max(dp[i], j*(i-j));
                dp[i] = max(dp[i], j*dp[i-j]);
                dp[i] = max(dp[i], dp[j]*(i-j));
                dp[i] = max(dp[i], dp[j]*dp[i-j]);
            }
        }
        return dp[n];
    }
};
View Code

354. Russian Doll Envelopes

题意:给定一组信封的长宽,长和宽都较小(没有等于,不能翻转)的信封可以放入较大的信封里,求最多可以嵌套多少个信封(顺序不一定是输入顺序)

我的思路:将一维从小到大排序后即可按照最长上升子序列来做了,但是有一个非常good的点是,将第二维从大到小排序,再套LCS的模板,即可避免第一维相等的问题

我的代码:记住sort函数cmp的写法

class Solution {
public:
    static bool cmp(const pair<int, int>& x, pair<int, int>& y) {
        return x.first != y.first ? x.first < y.first : x.second > y.second;
    }
    int maxEnvelopes(vectorint, int>>& envelopes) {
        int n = envelopes.size();
        if (n == 0) return 0;
        sort(envelopes.begin(), envelopes.end(), cmp);
        vector<int> dp(n);
        vector<int> g(n+1, 0x7fffffff);
        for (int i = 0; i < n; i++) {
            int k = lower_bound(g.begin()+1, g.end(), envelopes[i].second)-g.begin();
            dp[i] = k;
            g[k] = envelopes[i].second;
        }
        for (int i = 1; i < n; i++) dp[i] = max(dp[i], dp[i-1]);
        return dp[n-1];
    }
};
View Code

九章最优解:一样

bool cmp(const pair<int,int>&x, const pair<int, int>&y) {
  return x.first != y.first ? x.first < y.first : x.second > y.second;
}

class Solution {
public:
    /**
     * @param envelopes a number of envelopes with widths and heights
     * @return the maximum number of envelopes
     */
    int maxEnvelopes(vectorint, int>>& envelopes) {
        // Write your code here
        int n = envelopes.size();
        if (n == 0) {
            return 0;
        }
    
        sort(envelopes.begin(), envelopes.end(), cmp);
        vector<int> dp(n), height(n+1, INT_MAX);
        for (int i = 0; i < n; i++) {
            int k = lower_bound(height.begin(), height.end(), envelopes[i].second) - height.begin() ;
            dp[i] = k;
            height[k] = envelopes[i].second;
        }
    
        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans = max(ans, dp[i]);
        }
        return ans + 1;
    }
};
View Code

363. Max Sum of Rectangle No Larger Than K

题意:输出不超过k的最大子矩阵和

我的思路:最大子矩阵和+小于k的最大字段和问题,看过两个链接就很简单了https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/discuss/83599

我的代码:

class Solution {
public:
    vectorint>> transpos(vectorint>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        if (m <= n) return matrix;
        vectorint>> ret(n, vector<int>(m));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                ret[i][j] = matrix[j][i];
        return ret;
    }
    int maxSumSubmatrix(vectorint>>& matrix, int k) {
        vectorint>> s = transpos(matrix);
        int m = s.size(), n = s[0].size(), maxsum = 0x80000000;
        for (int i = 0; i < m; i++) {
            vector<int> sum(n, 0);
            for (int j = i; j < m; j++) {
                for (int kk = 0; kk < n; kk++) sum[kk] += s[j][kk];
                set<int> cumset;
                cumset.insert(0);
                int best = 0x80000000, cum = 0;
                for(int kk = 0;kk < n; kk++) {
                    cum += sum[kk];
                    set<int>::iterator sit = cumset.lower_bound(cum-k);
                    if(sit != cumset.end()) best = max(best, cum-*sit);
                    cumset.insert(cum);
                }
                maxsum = max(maxsum, best);
            }
        }
        return maxsum;
    }
};
View Code

368. Largest Divisible Subset

题意:求数组的最大子集,其中每对数字都可以整除

我的思路:dp,最长上升子串变体

我的代码:

class Solution {
public:
    vector<int> largestDivisibleSubset(vector<int>& nums) {
        int n = nums.size(), maxn = 1, k = 0;
        if (n == 0) return {};
        vector<int> dp(n, 1), loc(n), ans;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n; i++)
            for (int j = 0; j < i; j++)
                if (nums[i]%nums[j] == 0 && dp[j]+1 > dp[i]) {
                    dp[i] = dp[j]+1;
                    loc[i] = j;
                    if (dp[i] > maxn) {
                        maxn = dp[i];
                        k = i;
                    }
                }
        while (maxn--) {
            ans.push_back(nums[k]);
            k = loc[k];
        }
        return ans;
    }
};
View Code

375. Guess Number Higher or Lower II

题意:猜数,告诉高或者低,猜错罚相应点数,求最少需要准备多少点数可以猜出任意数

我的思路:记忆化搜索

我的代码:

class Solution {
public:
    int hehe(vectorint>>& dp, int l, int r) {
        if (l >= r) return 0;
        if (dp[l][r]) return dp[l][r];
        int ans = 0x7fffffff;
        for (int i = l; i <= r; i++)
            ans = min(ans, i+max(hehe(dp, l, i-1),hehe(dp, i+1, r)));
        dp[l][r] = ans;
        return ans;
    }
    int getMoneyAmount(int n) {
        vectorint>> dp(n+1, vector<int>(n+1, 0));
        return hehe(dp, 1, n);
    }
};
View Code

solution解法:自底向上循环

class Solution {
    int max(int a,int b)
    {
        return a>b?a:b;
    }
public:
    int getMoneyAmount(int n) {
        vectorint>> dp(n+1,vector<int>(n+1,0));
       
        for(int i=2;i<=n;++i)
        {
            for(int j=i-1;j>0;--j)
            {
                int global_min = INT_MAX;
                for(int k=j+1;kk)
                {
                    int tmp=k+max(dp[j][k-1],dp[k+1][i]);
                    if(tmptmp;
                }
                dp[j][i]=j+1==i?j:global_min;
            }
        }
        return dp[1][n];
    }
};
View Code

377. Combination Sum IV

题意:给定一个数组和一个和,数组元素不重复,求数组元素可反复使用情况下有多少种情况可以加得此和

我的思路:递推,类似走楼梯那题

我的代码:

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int> ans(target+1, 0);
        ans[0] = 1;
        for (int i = 1; i <= target; i++)
            for (int j = 0; j < nums.size(); j++)
                if (i-nums[j] >= 0) ans[i] += ans[i-nums[j]];
        return ans[target];
    }
};
View Code

九章最优解:完全一样

416. Partition Equal Subset Sum

题意:给定一个数组,问能否放成两堆(任意放,不是左右划分)使他们元素之和相等

我的思路:01背包,如果以总和的一半的容量来放这些数字,最多正好能放总和的一半,则可以划分成两部分

我的代码:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int vol = 0;
        for (int i = 0; i < nums.size(); i++) vol += nums[i];
        if (vol%2) return 0;
        vector<int> dp(vol/2+1);
        for (int i = 0; i < nums.size(); i++) {
            for (int v = vol/2; v >= nums[i]; v--) {
                dp[v] = max(dp[v], dp[v-nums[i]]+nums[i]);
            }
        }
        return dp[vol/2] == vol/2;
    }
};
View Code

九章最优解:思路一样,有个抑或操作不是很明白

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int len = nums.size();
        int sum = 0;
        for(int i=0; i< len ; i++){
            sum += nums[i];
        }
        if(sum % 2 == 1 ){
            return false;
        } 
        sum /= 2;
        int * dp = new int[20000];
        for(int i=0; i <=sum; i++)
            dp[i] = 0;
        dp[0] = 1;
        for(int i=0; i < len; i++){
            for(int j = sum;j >= nums[i]; j--){
                dp[j] |= dp[j - nums[i]];
            }
        }
        return dp[sum];
    }
};
View Code

solution解法:擦嘞

class Solution {
public:
  
    bool canPartition(vector<int>& nums) {
        bitset<10001> bits(1);
        int sum = accumulate(nums.begin(),nums.end(),0);
        for(auto n:nums) bits |= bits<<n;
        return !(sum&1)&&bits[sum>>1];
    }
    
    
};
View Code

474. Ones and Zeroes

题意:给定一组01串,问m个0、n个1最多能组成其中多少个

我的思路:二维背包

我的代码:

class Solution {
public:
    int num0(string s) {
        int ans = 0;
        for (int i = 0; i < s.size(); i++)
            if (s[i] == '0') ans++;
        return ans;
    }
    int findMaxForm(vector<string>& strs, int m, int n) {
        vectorint> > dp(m+1, vector<int>(n+1, 0));
        for (int i = 0; i < strs.size(); i++) {
            int cnt0 = num0(strs[i]), l = strs[i].size();
            for (int j = m; j >= cnt0; j--)
                for (int k = n; k >= l-cnt0; k--)
                    dp[j][k] = max(dp[j][k], dp[j-cnt0][k+cnt0-l]+1);
        }
            
        return dp[m][n];
    }
};
View Code

九章最优解:一样

solution解法:

class Solution {
public:
   int findMaxForm(vector<string>& strs, int m, int n) {
        vectorint, int>> nums(strs.size(), pair<int, int>{});
        for (int i = 0; i < strs.size(); ++i) nums[i] = count(strs[i]);
        sort(nums.begin(), nums.end(), [](const pair<int, int>& a, const pair<int, int>& b){
           return a.first < b.first || (a.first == b.first && a.second < b.second); 
        });
        int result = 0;
        for (int i = 0; i < nums.size(); i++) {
            result = max(result, helper(nums, m, n, i));
        }
        return result;
    }
    int helper(vectorint, int>>& nums, int m, int n, int start) {
        int cnt = 0;
        for (int i = start; i < nums.size(); i++) {
            if (nums[i].first <= m && nums[i].second <= n) {
                cnt++;
                m = m - nums[i].first;
                n = n - nums[i].second;
            }
        }
        return cnt;       
    }
    
    pair<int, int> count(string& s){
        int ones = 0, zeros = 0;
        for (char& c : s){
            if (c == '0') ++zeros;
            else ++ones;
        }
        return {zeros, ones};
    }
};
View Code

486. Predict the Winner

题意:给定一个数组,甲乙二人可以分别从首或者尾取一个数字,返回甲取得数字总和能否大于等于乙

我的思路:如果一方选择了两端的任意一个数,可以看成加,而另一方选择它的数对于自己来说可以看成是减。只要最后的结果不小于0,说明自己就比对手高。

我的代码:

class Solution {
public:
    int dp(int i, int j, vector<int>& nums, int flag) {
        if (i == j) return nums[i];
        if (flag) return max(dp(i+1, j, nums, flag^1)+nums[i], dp(i, j-1, nums, flag^1)+nums[j]);
        else return min(dp(i+1, j, nums, flag^1)-nums[i], dp(i, j-1, nums, flag^1)-nums[j]);
    }
    bool PredictTheWinner(vector<int>& nums) {
        return dp(0, nums.size()-1, nums, 1) >= 0;
    }
};
View Code

solution解法:减少了很多重复工作

class Solution {
public:
    int dp[30][30];
    int f(int l, int r, vector<int>& nums)
    {
        if (l == r) return nums[l];
        if (dp[l][r] != 0) return dp[l][r];
        dp[l][r] = max(nums[l] - f(l + 1, r, nums), nums[r] - f(l, r - 1, nums));
        return dp[l][r];
    }
    bool PredictTheWinner(vector<int>& nums) {
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < nums.size(); ++i) dp[i][i] = nums[i];
        return f(0, nums.size() - 1, nums) >= 0;
    }
};
View Code

494. Target Sum

题意:给定一个数组,可以在每个元素前乘+-1,求使得和为S的方案数

我的思路:暴搜所有情况

我的代码:

class Solution {
public:
    int ans;
    void dfs(vector<int>& nums, int i, int sum, int S) {
        if (i == nums.size()) {
            if (sum == S) ans++;
            return;
        }
        dfs(nums, i+1, sum+nums[i], S);
        dfs(nums, i+1, sum-nums[i], S);
    }
    int findTargetSumWays(vector<int>& nums, int S) {
        dfs(nums, 0, 0, S);
        return ans;
    }
};
View Code

solution解法:

1)暴力,如上

2)记忆化搜索

public class Solution {
    int count = 0;
    public int findTargetSumWays(int[] nums, int S) {
        int[][] memo = new int[nums.length][2001];
        for (int[] row: memo)
            Arrays.fill(row, Integer.MIN_VALUE);
        return calculate(nums, 0, 0, S, memo);
    }
    public int calculate(int[] nums, int i, int sum, int S, int[][] memo) {
        if (i == nums.length) {
            if (sum == S)
                return 1;
            else
                return 0;
        } else {
            if (memo[i][sum + 1000] != Integer.MIN_VALUE) {
                return memo[i][sum + 1000];
            }
            int add = calculate(nums, i + 1, sum + nums[i], S, memo);
            int subtract = calculate(nums, i + 1, sum - nums[i], S, memo);
            memo[i][sum + 1000] = add + subtract;
            return memo[i][sum + 1000];
        }
    }
}
View Code

3)二维dp

public class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int[][] dp = new int[nums.length][2001];
        dp[0][nums[0] + 1000] = 1;
        dp[0][-nums[0] + 1000] += 1;
        for (int i = 1; i < nums.length; i++) {
            for (int sum = -1000; sum <= 1000; sum++) {
                if (dp[i - 1][sum + 1000] > 0) {
                    dp[i][sum + nums[i] + 1000] += dp[i - 1][sum + 1000];
                    dp[i][sum - nums[i] + 1000] += dp[i - 1][sum + 1000];
                }
            }
        }
        return S > 1000 ? 0 : dp[nums.length - 1][S + 1000];
    }
}
View Code

4)二维缩减到1维,类似于背包那样

public class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int[] dp = new int[2001];
        dp[nums[0] + 1000] = 1;
        dp[-nums[0] + 1000] += 1;
        for (int i = 1; i < nums.length; i++) {
            int[] next = new int[2001];
            for (int sum = -1000; sum <= 1000; sum++) {
                if (dp[sum + 1000] > 0) {
                    next[sum + nums[i] + 1000] += dp[sum + 1000];
                    next[sum - nums[i] + 1000] += dp[sum + 1000];
                }
            }
            dp = next;
        }
        return S > 1000 ? 0 : dp[S + 1000];
    }
}
View Code

514. Freedom Trail

题意:转转轮拼出单词,至少需要转多少次,允许有重复字符

我的思路:dp,状态转移方程:

dp[k][i] = min(dp[k][i], dp[k - 1][j] + min(abs(i - j), len(ring) - abs(i - j))),其中k表示当前字符在key中的下标,i表示当前字符在ring中的下标,j表示上一个字符在ring中的下标。

代码:

class Solution {
public:
    int dfs(string r, string key, int ri) {
        if (key.length() == 0) return 0;
        int ans = 0x7fffffff;
        for (int i = 0; i < r.length(); i++) {
            if (r[(ri+i)%r.length()] == key[0])
                ans = min(ans, min(i, (int)r.length()-i)+1+dfs(r, key.substr(1, key.length()-1), (ri+i)%r.length()));
        }
        return ans;
    }
    int findRotateSteps(string ring, string key) {
        int m = ring.length(), n = key.length();
        vectorint>> dp(n+1, vector<int>(m));
        for (int i = n-1; i >= 0; i--)
            for (int j = 0; j < m; j++) {
                dp[i][j] = 0x7fffffff;
                for (int k = 0; k < m; k++)
                    if (ring[k] == key[i]) {
                        int diff = abs(j-k);
                        int step = min(diff,m-diff);
                        dp[i][j] = min(dp[i][j], step + dp[i + 1][k]);
                    }
            }
        return dp[0][0]+n;
    }
};
View Code

 

516. Longest Palindromic Subsequence

题意:返回最长回文子串长度

我的思路:dp,状态转移方程

if (s[j] == s[i+j]) dp[j][j+i] = max(dp[j][j+i], dp[j+1][j+i-1]+2);
else dp[j][j+i] = max(dp[j][j+i], dp[j+1][j+i-1]);

我的代码:

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n = s.size();
        if (n <= 1) return n;
        vectorint>> dp(n, vector<int>(n, 0));
        for (int i = 0; i < n; i++)
            for (int j = 0; j+i < n; j++) {
                if (i == 0) dp[j][j+i] = 1;
                else if (i == 1) dp[j][j+i] = (s[j] == s[j+i])+1;
                else {
                    dp[j][i+j] = max(dp[j+1][j+i], dp[j][j+i-1]);
                    if (s[j] == s[i+j]) dp[j][j+i] = max(dp[j][j+i], dp[j+1][j+i-1]+2);
                    else dp[j][j+i] = max(dp[j][j+i], dp[j+1][j+i-1]);
                }
            }
        return dp[0][n-1];
    }
};
View Code

solution解法:

int longestPalindromeSubseq(string s) {
        if (s.size() == 0) return 0;
        vector<int> dp(s.size(), 0);
        for (int i = s.size() - 1; i >=0; i--) {
            int prev = 1;
            for (int j = i + 1; j < s.size(); j++) {
                int curr;
                if (s[i] == s[j]) curr = 2 + dp[j - 1];
                else curr = max(prev, dp[j]);
                dp[j - 1] = prev;
                prev = curr;
            }
            dp[s.size() - 1] = prev;
        }
        return dp[s.size() -1];
    }
View Code

552. Student Attendance Record II

题意:求生成长度为n的一个字符串总共有多少种方法 ,要求:P无限放,A最多放1个,连续的L最多有两个

我的思路:看的disscussion的解法,非常好,后做了一个空间上的优化

class Solution {
public:
    int checkRecord(int n) {
        int MOD = 1000000007;
        vectorint> > > f (2, vectorint> >(2, vector<int>(3)));
        f[0] = {{1, 1, 1}, {1, 1, 1}};
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < 2; j++)
                for (int k = 0; k < 3; k++) {
                    int val = f[(i-1)%2][j][2]; // ...任何情况下都可以放P
                    if (j > 0) val = (val + f[(i-1)%2][j - 1][2]) % MOD; // ...i-1个没有A的时候可以放A
                    if (k > 0) val = (val + f[(i-1)%2][j][k - 1]) % MOD; // ...最多k-1个L的时候可以放L
                    f[i%2][j][k] = val;
                }
        return f[n%2][1][2];
    }
};
View Code

583. Delete Operation for Two Strings

题意:两个字符串经过多少次删除操作可以变成一样的

我的思路:lcs

我的代码:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word1.size(), n = word2.size();
        vectorint> > dp(m+1, vector<int>(n+1));
        dp[0][0] = 0;
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++) {
                if (word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1]+1;
                else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        return m+n-2*dp[m][n];
    }
};
View Code

623. Add One Row to Tree

题意:在树的某一层加一层某值

我的思路:常规树dfs

我的代码:

class Solution {
public:
    void dfs(TreeNode* root, int v, int d, int i) {
        if (i == d-1) {
            TreeNode* tmpl = new TreeNode(v);
            tmpl->left = root->left;
            root->left = tmpl;
            TreeNode* tmpr = new TreeNode(v);
            tmpr->right = root->right;
            root->right = tmpr;
        } else if (i < d-1) {
            if (root->left) dfs(root->left, v, d, i+1);
            if (root->right) dfs(root->right, v, d, i+1);
        }
    }
    TreeNode* addOneRow(TreeNode* root, int v, int d) {
        if (d == 1) {
            TreeNode* tmp = new TreeNode(v);
            tmp->left = root;
            return tmp;
        }
        if (root) dfs(root, v, d, 1);
        return root;
    }
};
View Code

646. Maximum Length of Pair Chain

题意:给定一组区间,求最长的区间链(前一个区间尾小于后一个区间头)

我的思路:LCS模板题

我的代码:没用logn优化

class Solution {
public:
    static bool cmp(const vector<int> &a, const vector<int> &b) {
        return a[0] == b[0] ? a[1]1] : a[0]0];
    }
    int findLongestChain(vectorint>>& pairs) {
        if (pairs.size() <= 1) return pairs.size();
        vector<int> dp(pairs.size(), 1);
        int ans = 0;
        sort(pairs.begin(), pairs.end(), cmp);
        for (int i = 1; i < pairs.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (pairs[j][1] < pairs[i][0])
                    dp[i] = max(dp[i], dp[j]+1);
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};
View Code

solution解法:

bool comp(pair<int, int>a, pair<int, int>b) {
    return a.second < b.second;
}

class Solution {
public:
    int findLongestChain(vectorint>>& pairs) {
        
        vectorint, int>> v;
        for (int i = 0; i < pairs.size(); ++i) {
            v.push_back(make_pair(pairs[i][0], pairs[i][1]));
        }
        sort(v.begin(), v.end(), comp);
        for (int i = 0; i < pairs.size(); ++i) {
            pairs[i][0] = v[i].first;
            pairs[i][1] = v[i].second;
        }        
        int a = 1;
        pair<int, int> p = v[0];
        for (int i = 1; i < v.size(); ++i) {
            if (v[i].first > p.second) {
                a++;
                p = v[i];
            }
        }
        return a;
    }
};
View Code

756. Pyramid Transition Matrix

题意:给定最底层和所有两个字母之上可以放置的模式,问能否构成金字塔

思路: https://segmentfault.com/a/1190000012727144

我的代码:

class Solution {
public:
    bool pyramidTransition(string bottom, vector<string>& allowed) {
        int n = bottom.length();
        unordered_map<string, vector<char>> mp;
        vectorset<char>>> dp(n, vector<set<char>>(n));
        for (int i = 0; i < allowed.size(); i++)
            mp[allowed[i].substr(0, 2)].push_back(allowed[i][2]);
        for (int i = 0; i < n; i++) dp[0][i].insert(bottom[i]);
        for (int i = 1; i < n; i++)
            for (int j = 0; j < n-i; j++)
                for (char a: dp[i-1][j])
                    for (char b: dp[i-1][j+1]) {
                        string s;
                        s = s+a+b;
                        for (char c: mp[s]) dp[i][j].insert(c);
                    }
        return !dp[n-1][0].empty();
    }
};
View Code

 

转载于:https://www.cnblogs.com/hqxue/p/6618868.html

你可能感兴趣的:(一刷leetcode——dp)