每日一题:大礼包

2021年10月24日每日一题:
:大礼包问题
难度:中等
感悟:一顿操作猛如虎,bug查得真辛苦。思路好像都一样,一看细节多到吐。
官方题解:记忆搜索

class Solution {
public:
    map<vector<int>, int> memo; //记录needs的状态和此状态下的最优解

    int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
        int n = price.size(); //商品数量

        // 过滤不需要计算的大礼包,只保留需要计算的大礼包
        vector<vector<int>> filterSpecial;
        for (auto & sp : special) {
            int totalCount = 0, totalPrice = 0;
            for (int i = 0; i < n; ++i) {
                totalCount += sp[i];            //大礼包里总的商品数量
                totalPrice += sp[i] * price[i]; //大礼包里的商品如果原价买所需钱
            }
            if (totalCount > 0 && totalPrice > sp[n]) { //大礼包里确定有商品and价格比原价购买低
                filterSpecial.emplace_back(sp);  //这个大礼包可以考虑,加入候选队伍
            }
        }

        return dfs(price, special, needs, filterSpecial, n); //用dfs计算最优解
    }

    // 记忆化搜索计算满足购物清单所需花费的最低价格
    int dfs(vector<int> price,const vector<vector<int>> & special, vector<int> curNeeds, vector<vector<int>> & filterSpecial, int n) {
        if (!memo.count(curNeeds)) {  //确定此need状态没有遇见过(记忆)
            int minPrice = 0;         //最优解
            for (int i = 0; i < n; ++i) {
                minPrice += curNeeds[i] * price[i]; // 不购买任何大礼包,原价购买购物清单中的所有物品
            }
            for (auto & curSpecial : filterSpecial) {  //
                int specialPrice = curSpecial[n];      //大礼包价格
                vector<int> nxtNeeds;                  //记录need状态
                for (int i = 0; i < n; ++i) {
                    if (curSpecial[i] > curNeeds[i]) { // 不能购买超出购物清单指定数量的物品
                        break;
                    }
                    nxtNeeds.emplace_back(curNeeds[i] - curSpecial[i]); //改变need状态
                }
                if (nxtNeeds.size() == n) { // 大礼包可以购买
                    minPrice = min(minPrice, dfs(price, special, nxtNeeds, filterSpecial, n) + specialPrice);  //改变need状态后再次进入dfs进行计算
                }
            }
            memo[curNeeds] = minPrice;   //记录此need状态的最优解
        }
        return memo[curNeeds];
    }
};

复盘:算法不会,思想有的,看到题,哐哐哐,很快就写出来代码,想法是

  1. 判断出符合的大礼包
  2. 把大礼包的数量扣了,剩下的原价购买,再加上大礼包的钱,就是答案
  3. 错误点:可以买多个一样大礼包,我默认只能买一个礼包
  4. 修改:求needs/大礼包的商品的最小公约数,用最小公约数来求大礼包数量
  5. 错误点:可以不同的大礼包结合,我默认只能买一种礼包
  6. 修改:不会了
    官方题解思路:
    1.找到符合条件的大礼包–有商品and大礼包的商品原价购买比大礼包贵
    2.使用记忆搜索,找到最优解
    记忆搜索:
    1.记忆下need扣除大礼包后的状态。
    2.回溯来穷举所有的大礼包和原价的组合情况。

思路差距:没有想到记忆搜索和回溯,看到题第一感觉就是遍历来不断判断情况,遇到最后一个问题,即可以不同的礼包相结合时,没有想到递归回溯的办法,依然想着遍历安判断。

学习了:当有不同的组合时,记住可以使用递归回溯来穷举出所有组合,记忆化搜索可以省去很多时间。遇见题不要老想着遍历,想好了题目里的所有情况再动手,不然就会不断出现bug。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值