草庐IT

力扣 297 场周赛

ViTe思考者 2023-09-21 原文

力扣 297 场周赛

第一题

解法:模拟

  • 时间复杂度 O(N)
  • 空间复杂度 O(N)
class Solution {
public:
    double calculateTax(vector<vector<int>>& bs, int ie) {
        double ret = 0;
        bs.push_back({0, 0});
        sort(bs.begin(), bs.end(), [](vector<int>& a, vector<int>& b) {
            return a[0] < b[0];
        });
        for (int i = 0; i < bs.size(); ++ i) {
            // cout << ie << " " << bs[i + 1][0] << " " << bs[i][0] << endl;
            if (i == bs.size() - 1) {
            }else {
                if (ie >= bs[i + 1][0]) {
                    ret += (double)(bs[i + 1][0] - bs[i][0]) * bs[i + 1][1] / 100;
                    
                    
                }else {
                    ret += ((double)ie - bs[i][0]) * bs[i + 1][1] / 100;
                    break;
                }
            }
            // cout << ret << endl;
        }
        return ret;
    }
};

第二题

解法:线性 DP
  dist[i] 表示 i 这个点到最底层的距离

  • 时间复杂度 O(N * M ^ 2)
  • 空间复杂度 O(N)
class Solution {
    
public:
    unordered_map<int, int> row;
    int dist[3000];
    int n, m;
    int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& mt) {
        vector<int> one, last;
        for (int i = 0; i < grid.size(); ++ i) {
            for (int& j : grid[i]) {
                row[j] = i;
                if (i == 0) one.push_back(j);
                if (i == grid.size() - 1) last.push_back(j);
            }
        }
        memset(dist, 0x3f, sizeof dist);
        for (int& x : last) dist[x] = 0;
        int n = grid.size();
        for (int i = n - 2; i >= 0; -- i) {
            for (int j = 0; j < grid[i].size(); ++ j) {
                int x = grid[i][j];
                for (int k = 0; k < grid[i + 1].size(); ++ k) {
                    int v = grid[i + 1][k];
                    dist[x] = min(dist[x], v + mt[x][k] + dist[v]);
                    // dist[x] += dist[v];
                }    
                
            }
        }
        int ret = 1e9;
        // cout << dist[0] << " " << dist[4] << endl;
        for (int& i : one) {
            // cout << i << " " << dist[i] << endl;
            ret = min(ret, dist[i] + i);
        }
        return ret;
    }
};

第三题

解法 1: 回溯
 搜索每包零食分给每个朋友, 每包零食有 K 种选择;

  • 时间复杂度 O(N ^ k)
  • 空间复杂度 O(N)
class Solution {
    int n, K, ans;
    vector<int> A, tot;

    void dfs(int d) {
        if (d == n) {
            // 所有零食都分完了,计算小朋友获得的最大饼干数
            int t = tot[0];
            for (int i = 1; i < K; i++) t = max(t, tot[i]);
            // 所有结果里取最小
            ans = min(ans, t);
            return;
        }

        for (int i = 0; i < K; i++) {
            // 枚举第 d 包零食分给第 i 个小朋友
            tot[i] += A[d];
            dfs(d + 1);
            // 撤销修改
            tot[i] -= A[d];
        }
    }

public:
    int distributeCookies(vector<int>& cookies, int k) {
        n = cookies.size(); K = k;
        A = cookies; tot.resize(K, 0);
        ans = 1e9; dfs(0);
        return ans;
    }
};

作者:TsReaper
链接:https://leetcode.cn/circle/discuss/4GGKMb/view/OxXY76/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解法2:二分 + 回溯
 二分最大不公上限,回溯是否有满足此上限的分配方案

  • 剪枝 1:优先分配饼干包数最多的
     对饼干从大到小排序
  • 剪枝 2:第一个零食包不管给哪个小朋友,所开启的回溯树都一样,所以首个饼干包只要给第一个小朋友就行了,这样的回溯树只有一个根节点(一个回溯树),否则有k个回溯树。
  • 剪枝 3:如果当前小朋友没有分配饼干或分配包数达到上限则无需进行下一个朋友分配(具体见代码)

参考

  • 时间复杂度 O(N * log N)
  • 空间复杂度 O(N)
class Solution {
public:
    bool check(vector<int>& cs, vector<int>& bk, int u, int m) {
        if (u == cs.size()) return true;
        for (int i = 0; i < bk.size(); ++ i) {
            // 剪枝 2
            if (i && bk[i] == bk[i - 1]) continue;
            bk[i] += cs[u];
            if (bk[i] <= m && check(cs, bk, u + 1, m)) {
                bk[i] -= cs[u];
                return true;
            }
            bk[i] -= cs[u];
            // 剪枝 3
            if (bk[i] == 0 || bk[i] + cs[u] == m) break;
        }
        return false;
        
    }
    int distributeCookies(vector<int>& cs, int k) {
        // 剪枝 1
        sort(cs.begin(), cs.end(), [](int& a, int& b){
            return a > b;
        });
        int sum = 0;
        for (int& x : cs) sum += x;
        int l = 1, r = sum;
        vector<int> bk(k);
        while (l < r) {
            int mid = l + r >> 1;
            if (check(cs, bk, 0, mid)) {
                r = mid;
            }else l = mid + 1;
        }
        return l;
    }
};

解法3:状态压缩 DP
  dp[i][j] 为前 i 个朋友分配情况为 j 时的最小不公值, 答案为 dp[k][(1 << n) - 1];有 dp[i][j] = min(dp[i][j], max(dp[i][j - x], sum[x]));
其中 j 为二进制表示饼干分配情况比如 1010,表示分配了第零个饼干和第二个饼干
sum[x] 表示分配情况为 x 的累加和比如 1010 表示 cookies[0] + cookies[2];

class Solution {
public:
    int distributeCookies(vector<int>& cs, int k) {
        int n = cs.size();
        vector<vector<int> > dp(k,  vector<int>(1 << n, 1e8));
        vector<int> sum(1 << n);
        for (int i = 0; i < 1 << n; ++ i) {
            for (int j = 0; j < n; ++ j) {
                if (i >> j & 1) {
                    sum[i] += cs[j];
                }
            }
        }

        for (int i = 0; i < 1 << n; ++ i) {
            dp[0][i] = sum[i];
        }
  
        for (int i = 1; i < k; ++ i) {
            for (int j = 0; j < 1 << n; ++ j) {
            
                for (int x = j; x; x = (x - 1) & j) {
                    // 枚举 j 状态的子集
                    dp[i][j] = min(dp[i][j], max(dp[i - 1][j - x], sum[x]));
                }
            }
        }
    /*
for (int x = j; x; x = (x - 1) & j) 这样可以枚举状态j的每一个子集
比如 j = 3 (011) 这个循环就可以枚举 011, 010, 001这三个状态(用x表示)
(进入循环 x = 011,第一次 x = 010 & 011 = 010,第二次 x = 001 & 011 = 001)
比如 j = 4 (100) 这个循环只能枚举 100这个状态, x = (011) & (100)就会使x为0,从而退出循环。

max(dp[i - 1][j - x], sum[x]),就表示在 
给第 i 个朋友 分配 状态为 x 的饼干包数 
与
给前 i - 1朋友分配 状态为 j -x 的饼干的个人最小包数中 取最大值。
j - x 可以算 状态 x 在 j 下的 “补集”。比如 j 为 (110),x 为(010)时,j - x =(110 - 010 = 100)
枚举所有状态,取可能达到的个人最大包数的最小值,就可以求出满足题意的结果。
最后返回 dp[k - 1][(1<< n) - 1] 表示给k个朋友分配状态为 “111...1”的饼干,个人最大包数的最小值。
        */
        
        return dp[k - 1][(1 << n) - 1];
        
    }
};

第四题

解法:枚举
 按去除首字母后的字符串进行分组
cnt[i][j] 表示首字符不包含 i 字符且包含 j 字符的分组数目
若两个组能交换必然 一个有 j 无 i(cnt[i][j]) ,一个 有 i 无 j(cnt[j][i])
则 答案为所有 cnt[i][j] + cnt[j][i] 的和

class Solution {
public:
    long long distinctNames(vector<string>& is) {
        unordered_map<string, int> mp;
        for (string s : is) {
            mp[s.substr(1)] |= 1 << (s[0] - 'a');
        }
        
        int cnt[26][26];
        memset(cnt, 0, sizeof cnt);
        long long ret = 0;
        for (auto& [_, mask] : mp) {
            for (int i = 0; i < 26; ++ i) {
                if ((mask >> i & 1) == 0) {
                    for (int j = 0; j < 26; ++ j) {
                        if (mask >> j & 1) {
                            ++ cnt[i][j];
                        }
                    }
                }
            }
        }
        for (auto& [_, mask] : mp) {
            for (int i = 0; i < 26; ++ i) {
                if (mask >> i & 1) {
                    for (int j = 0; j < 26; ++ j) {
                        if ((mask >> j & 1) == 0) {
                            ret += cnt[i][j];
                            // cout << cnt[i][j] << endl;
                        }
                    }
                }
            }
        }
        return ret;
    }
};

有关力扣 297 场周赛的更多相关文章

  1. 2022年10月23日周赛ZZULIOJ - 2

    文章目录问题B:芝华士威士忌和他的小猫咪们代码&注释问题C:愿我的弹雨能熄灭你们的痛苦代码注释问题D:猜糖果游戏代码注释问题E:有趣的次方代码注释问题F:这是一个简单题代码&注释问题G:打印矩阵代码注释问题H:scz的简单考验代码注释问题I:完美区间代码&注释问题J:是狂热的小迷妹一枚吖~代码&注释2022年10月23日周赛ZZULIOJ问题B:芝华士威士忌和他的小猫咪们时间限制:1Sec内存限制:128MB题目描述芝华士威士忌很喜欢带着他的猫咪们一块跑着玩。但是小猫咪们很懒,只有在离他y米以内才愿意和他一块跑。这天他在坐标为x的位置,他想和他的猫咪们一块跑着玩。有n个小猫咪,第i个小猫咪在坐

  2. 面试总结+力扣第二天刷题 - 2

    一.面试总结    4月20号下午进行了一场大数据视频面试,总结一下踩坑点:    1.确定面试后,第一件事要和HR确定面试方式,具体时间、地点、什么软件、岗位JD等必须信息。        这里很多人有一个思想误区,认为问的太多会给HR不好的印象;其实大可不必,如果你通过了简历筛选,你就有权力使用公司招聘的人力资源。    2.要在面试10分钟前就进入面试的环境中,以防突发事件。    3.面试最开始都会有一个自我介绍环节,这个自我介绍环节,一定要慎之又慎,最好写下来,让朋友、长辈等审核多遍。    注:我面试时,在这踩了一个坑,自我介绍的时候踩了我要面试的岗位一脚,被技术面试官抓住了这一点

  3. 【Java牛客&力扣刷题特辑第五期】——诸佬们这些坑你们都踩过了吗?牛客网经典笔试题目每天刷两道,快乐充实一整天 - 2

    ✨✨【Java牛客&力扣刷题特辑第五期】——诸佬们这些坑你们都踩过了吗?✔✨前言🎉🎉大家好!好久不见我是青花瓷,今天你刷题了吗?文章目录,从易到难,层层递进,如果每一道题都吃透,你一定会在做题方面有质的飞跃,关注我,一起学习算法,一起分享好的题型。博主将持续更新算法,大厂笔试题,经典算法题,易错题,如果觉得不错,点点赞支持一下,如果有错误的地方,欢迎指正✨✨下一期:算法篇之回溯算法作者介绍:🎓作者:偷偷敲代码的青花瓷✨👀作者的Gitee:代码仓库📌系列文章推荐:✨1.Java牛客&力扣刷题特辑第一期✨2.Java牛客&力扣刷题特辑第二期✨3.Java牛客&力扣刷题特辑第三期✨4.Java牛客&

  4. 【力扣精选】3分钟拿下反转链表所有题型 - 2

    🥪写在前面Hello朋友们😋,我是秋刀鱼🐟,一只活跃于Java区与算法区的新人博主~欢迎大家加入高校算法学习社区🏰:https://bbs.csdn.net/forums/Suanfa,社区里大佬云集,大家互相交流学习!从今天开始我将陆续更新《轻松拿捏大厂面试题》专栏文章,本专栏将挑选大厂出现频率极高的面试题做专题解读,本篇也是专栏的第一篇《反转链表篇》。🎉🎉主页:秋刀鱼与猫🎉🎉🎉🎉期待你的支持与关注~🎉🎉🍥目录🥪写在前面🍔反转链表🥗题目描述🌮解题分析🧀参考代码(Java语言)🍟反转链表II🥗题目描述🌮解题分析🧀参考代码(Java语言)🍕K个一组反转链表🥗题目描述🌮解题分析🧀参考代码(Java

  5. Acwing 第 91 场周赛 - 2

    Poweredby:NEFUAB-INB站直播录像!Link文章目录Acwing第91场周赛AAcWing4861.构造数列题意思路代码BAcWing4862.浇花题意思路代码CAcWing4863.构造新矩阵题意思路代码Acwing第91场周赛AAcWing4861.构造数列题意略思路将每个数的每一位全部拆出来即可代码/**@Author:NEFUAB-IN*@Date:2023-02-1818:59:30*@FilePath:\Acwing\91cp\a\a.cpp*@LastEditTime:2023-02-1819:03:25*/#includeusingnamespacestd;#d

  6. 栈和队列的相互实现(力扣225、232) - 2

    目录栈和队列的区别:栈实现队列:题目描述:示例:画图解释:代码实现:队列实现栈:题目描述:示例:解法一:双队列实现栈代码实现:解法二:单队列实现栈代码实现:栈和队列的区别:队列和栈是两种不同的数据结构。它们有以下区别:(1)操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。(2)可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。(3)操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(

  7. 【力扣刷题】整数拆分(动态规划) - 2

     个人简历:全栈领域新星博主,万粉博主、帮助初学者入门,记录自己的学习过程个人主页:天寒雨落的博客_CSDN博客-C,CSDN竞赛,python领域博主热门专栏:初学者入门C语言_天寒雨落的博客-CSDN博客 目录动态规划整数拆分题目思路代码执行结果动态规划其基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,经分解得到子问题往往不是互相独立的,举个简单的例子:你知道两个1相加等于2,问你三个1相加你是拿前面的两个1相加的结果加上1呢,还是再用1+1+1,你肯定会用前面的那种方法对吧,这就是动态规划,(1+1)就是(1+1+1)的子问题,且并不是相互独立

  8. 【力扣-876】链表的中间结点 - 2

    🖊作者:Djx_hmbb📘专栏:数据结构😆今日分享:----------小Tips:虽然都是口服液体制剂,且看起来单支容量都一样,但是“藿香正气水”与“藿香正气口服液”的区别你知道吗?藿香正气水里含有40%-50%的乙醇,而藿香正气口服液不含有乙醇。同时藿香正气水不能和头孢一起服用(因为含有酒精),而藿香正气口服液可以和头孢一起服用。文章目录✔题目链接:✔题目:✔解题思路:遍历两次:先计算链表长短,再将指针移到该位置遍历一次:设计一个快指针(步长=2)和一个慢指针(步长=1)✔遍历两次-->代码详情:✔遍历一次-->代码详情:✔图解:家人们,点个![请添加图片描述](https://img-b

  9. 力扣刷题篇之《空白替换》 - 2

    前言❤️铁汁们大家好,欢迎大家来到出小月的博客里,今天小月呢写了一道题目叫替换空格,但是呢,写完之后调试了半天不知道哪里错了,经过小月的坚持不懈,终于成功,来分享给大家小月的错误,希望大家看完我这篇文章都能够“涨芝士”,感觉小月写的还不错的话,记得👍🏻点赞加关注😘鼓励一下博主哦,不然下次可找不到我啦❗❗作者简介❤️作者的主页:出小月的《程序员历险记》❤️专栏:《C语言》,《数据结构初阶》😊希望大家都能够:好好学习,天天编程❗❗❗文章目录前言作者简介一、题目介绍二、题目链接三、小月的思路四、小月出现的错误错误1错误2五、正确代码总结一、题目介绍🐻请实现一个函数,把字符串s中的每个空格替换成"%2

  10. 【力扣刷题笔记】由简到难,模块突破, 你与AC只差一句提示 - 2

    必会基础部分👇👇👇👇👇👇,可以收藏下来慢慢看。文章目录一、易懂贪心算法分配问题455.分发饼干分发糖果区间问题435.无重叠区间练习题605.种花问题452.用最少数量的箭引爆气球763.划分字母区间122.买卖股票最佳时机Ⅱ406.根据身高重建队列665.非递减数列二、玩转双指针经典题目167.两数之和Ⅱ88.合并两个有序数组142.环形链表Ⅱ76.最小覆盖子串练习题680.验证回文字符串Ⅱ633.平方数之和524.通过删除字母匹配到字典里最长单词三、二分查找经典题目69.x的平方根34.在排序数组中查找元素的第一个和最后一个位置81.搜索旋转排序数组Ⅱ练习题目154.寻找旋转排序数组的最小

随机推荐