LeetCode动态规划第四天(补):Coin Change & Maximal Square

最近刷题有点恶心了,应该是低效思考时间过多,时间跨度大但是效果低下导致的惩罚效应。想题目的时候尽量保持好的状态。

322. Coin Change


思路一

没有很好的分辨出暴力法和bottom-up在复杂度上的差异,使用递归强行暴力,超时。其中还有想过用贪婪算法,尽可能使用较大的货币,但后来给出反例[1, 3, 11, 12] 15导致贪心失败。
复杂度差异:暴力方法无法知道分解到当前步骤是否已经说明不能继续分解了,还是会继续循环递归直到最后;自下而上则在每一次分解之后都可以明确知道是否已经走了死路。举例说明[3, 11, 12] 15, 当15 = 11 + 4时,4已经明确不能分解,而暴力法会继续4 = 3 +1,到1的时候才放弃。

代码

class Solution {
public:
    int coinCombine(vector<int>& coins, int amount) {
        if (coins.size() == 1) {
            if (amount % coins[0] == 0) return amount / coins[0];
            else return -1;
        }
        vector<int> vec(coins.begin(), coins.end()-1);
        int result = INT_MAX;
        for (int i = amount / coins.back(); i >= 0 ; i--) {
            int ret = coinCombine(vec, amount - i * coins.back());
            if (ret == -1) continue;
            result = min(result, ret + i);
        }
        if (result == INT_MAX) return -1;
        return result;
    }              

   int coinChange(vector<int>& coins, int amount) {
        sort(coins.begin(), coins.end());
        return coinCombine(coins, amount);
    }
};

思路二

典型的自下而上的策略。

代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(1, 0);
        for (int i = 1; i <= amount; i++) {
            int num = INT_MAX;
            for (int j = 0; j < coins.size(); j++) {
                if (i < coins[j] || dp[i - coins[j]] == -1) continue;
                num = min(num, dp[i - coins[j]] + 1);
            }
            if (num == INT_MAX) dp.push_back(-1);
            else dp.push_back(num);
        }
        return dp.back();
    }
};

221. Maximal Square


思路一

每一次只考虑将原来的矩阵向右下增加一行一列,状态保存为符合要求的方向左上角点坐标。
过程中犯了几个错误:
1. 循环中做判断的变量expand,没有在每一次循环开始前重新初始化;
2. 边界问题(即第一行)一开始认为可以通过循环条件hold住,没有考虑y_len在输入为[]时的特殊情况

代码

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if (matrix.size() == 0) return 0;
        vector<pair<int, int>> point;
        int x_len = matrix.size(), y_len = matrix[0].size();
        for (int x = 0; x < x_len; x++) {
            for (int y = 0; y < y_len; y++) {
                point.push_back(pair<int, int>(x, y));
            }
        }
        for (int l = 1; l <= min(x_len, y_len); l++) {
            vector<pair<int, int>> v;
            for (pair<int, int> p: point) {
                 bool expand = true;
                if (p.first+l-1 < x_len && p.second+l-1 < y_len) {
                    for (int x = p.first; x < p.first+l && expand; x++) {
                        if (matrix[x][p.second+l-1] == '0') expand = false;
                    }
                    for (int y = p.second; y < p.second+l && expand; y++) {
                        if (matrix[p.first+l-1][y] == '0') expand = false;
                    }
                    if (expand) v.push_back(p);
                }
            }
            point = v;
            if (point.size() == 0) return (l-1)*(l-1);
        }
        return min(x_len, y_len) *min(x_len, y_len);
    }
};

思路二

写完之后总觉得过于繁琐了,查了一下别人的做法果然惊艳到。维护一个二维数组dp,其中dp[i][j]代表以(i, j)作为正方形右下角中可以允许的最大边长。不仅代码简洁,逻辑清楚,而且复杂度也低。暂时不贴代码,等一天后自己再写

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值