力扣 297 场周赛

力扣 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;
    }
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容