【LeetCode第297场周赛】

A.

模拟即可,注意刚开始设置起征点为 0 0 0,减少边界处理问题。

class Solution {
public:
    double calculateTax(vector<vector<int>>& brackets, int income) {
        long long ans = 0;
        int pre = 0;
        for (auto &u : brackets) {
            int c = min(income - pre, u[0] - pre);
            ans += u[1] * c;
            if (income <= u[0]) break;
            pre = u[0];
        }
        return 1.0 * ans / 100.0;
    }
};

B.

数字三角形的变种
f [ i ] [ j ] f[i][j] f[i][j] 表示从第 1 1 1 行到第 i i i 行第 j j j 个需要的最小路径代价。
f [ i ] [ j ] = m i n { f [ i − 1 ] [ k ] + m o v e C o s t [ g r i d [ i − 1 ] [ k ] ] [ j ] } + g r i d [ i ] [ j ] f[i][j]=min\{ f[i-1][k]+moveCost[grid[i - 1][k]][j]\}+grid[i][j] f[i][j]=min{f[i1][k]+moveCost[grid[i1][k]][j]}+grid[i][j]
注意每次只从上一行转移过来,所以只需要两层即可。

class Solution {
public:
    int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& moveCost) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<int>> f(2, vector<int>(m, 0x3f3f3f3f));
        for (int j = 0; j < m; ++j) f[0][j] = grid[0][j];
        
        for(int i = 1; i < n; ++i) 
            for (int j = 0; j < m; ++j) {
                int minv = 0x3f3f3f3f;
                for (int k = 0; k < m; ++k)
                    minv = min(minv, f[i - 1 & 1][k] + moveCost[grid[i - 1][k]][j]);
                f[i & 1][j] = minv + grid[i][j];
            }
        
        int ans = 0x3f3f3f3f;
        for (int j = 0; j < m; ++j) ans = min(ans, f[n - 1 & 1][j]);
        
        return ans;
    }
};

C.

显然爆搜,可以加一个剪枝优化,即当已经存在一个学生被分配到的饼干数大于等于答案数时,就可以直接剪掉,因为这不会使得答案更小。

亦或是二分答案,同时可以加上上述优化

直接爆搜剪枝:

class Solution {
public:
    
    int ans;
    int n, k;
    vector<int> c;
    vector<int> sum;
    
    void dfs(int u) {
        if (u == n) {
            int res = 0;
            for (int i = 0; i < k; ++i)
                res = max(res, sum[i]);
            ans = min(ans, res);
            return ;
        }
        
        for (int i = 0; i < k; ++i) {
            if (sum[i] + c[u] < ans) {
                sum[i] += c[u];
                dfs(u + 1);
                sum[i] -= c[u];
            }
        }
    }
    
    int distributeCookies(vector<int>& cookies, int kk) {
        ans = 0x3f3f3f3f;
        c = cookies;
        k = kk;
        n = cookies.size();
        sum = vector<int>(k, 0);
        dfs(0);
        return ans;
    }
};

二分答案,check时剪枝优化

class Solution {
public:
    
    int ans;
    int n, k;
    vector<int> c;
    vector<int> sum;
    int maxv;
    
    bool dfs(int u) {
        if (u == n) {
            int res = 0;
            for (int i = 0; i < k; ++i)
                res = max(res, sum[i]);
            return res <= maxv;
        }
        
        for (int i = 0; i < k; ++i) {
            if (sum[i] + c[u] <= maxv) {
                sum[i] += c[u];
                bool ok = dfs(u + 1);
                sum[i] -= c[u];
                if (ok) return true;
            }
        }
        return false;
    }
    
    bool check(int v) {
        maxv = v;
        return dfs(0);
    }
    
    int distributeCookies(vector<int>& cookies, int kk) {
        ans = 0x3f3f3f3f;
        c = cookies;
        k = kk;
        n = cookies.size();
        sum = vector<int>(k, 0);
        
        int L = *max_element(cookies.begin(), cookies.end());
        int R = accumulate(cookies.begin(), cookies.end(), 0);
        while (L < R) {
            int mid = L + R >> 1;
            if (check(mid)) R = mid;
            else L = mid + 1;
        }
        
        return L;
    }
};

D.

先计算出字符串 s s s 允许哪些字符交换过来,同时计算有这些字符的串 t t t 多少可以接受 s [ 0 ] s[0] s[0]即可。

class Solution {
public:
    long long distinctNames(vector<string>& ideas) {
        map<string, int> mp;
        vector<int> c(26, 0);
        vector<vector<int>> no(26, vector<int>(26, 0));
        for (auto& u : ideas) {
        	// mp 记录所有 u.substr(1) 的出现过的首字符
            mp[u.substr(1)] |= 1 << (u[0] - 'a');
        }
        
        for (auto& u : ideas) {
        	int id = u[0] - 'a';
        	// c 记录有 u[0] 这个首字符的串的个数
        	c[id] += 1;
        	int x = mp[u.substr(1)];
        	for (int j = 0; j < 26; ++j)
        		// no 记录所有向外提供 u[0],但是不接受字符 (j+'a')的串的个数
        		if (x >> j & 1) no[id][j] += 1;
		}
        
        int n = ideas.size();
        
        long long ans = 0;
        for (int i = 0; i < n; ++i) {
            int x = (1 << 26) - 1 - mp[ideas[i].substr(1)];
            for (int j = 0; j < 26; ++j)
            	// 计算所有可以提供 (j+'a') 的同时可以接受 ideas[i][0]的串的个数
                if (x >> j & 1) ans += c[j] - no[j][ideas[i][0] - 'a'];
        }
        
        return ans;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值