LeetCode --- 414周赛

打印 上一主题 下一主题

主题 532|帖子 532|积分 1596

题目列表

3280. 将日期转换为二进制表现
3281. 范围内整数的最大得分
3282. 到达数组末了的最大得分
3283. 吃掉所有兵需要的最多移动次数
一、将日期转换成二进制表现


题目本质就是将数字转成二进制字符串,可以类比将十进制数字的每一位拆开拼成字符串,直接模拟即可,代码如下
  1. class Solution {
  2.     string get(string s){
  3.         int x = stoi(s);
  4.         string ans;
  5.         while(x){
  6.             ans += (x & 1) + '0';
  7.             x >>= 1;
  8.         }
  9.         reverse(ans.begin(),ans.end());
  10.         return ans;
  11.     }
  12. public:
  13.     string convertDateToBinary(string date) {
  14.         // int pos1 = date.find('-');
  15.         // int pos2 = date.rfind('-');
  16.         // return get(date.substr(0, pos1)) + '-'
  17.         //     + get(date.substr(pos1+1,pos2-pos1-1)) + '-'
  18.         //     + get(date.substr(pos2+1));
  19.         // 当然我们也可以直接观察字符串的格式,对字符串进行切割
  20.         return get(date.substr(0, 4)) + '-'
  21.             + get(date.substr(5, 2)) + '-'
  22.             + get(date.substr(8));
  23.     }
  24. };
复制代码
二、范围内整数的最大得分


看到最大最小,就要想到二分,然后我们来判断这题能否用二分来写,即判断是否具有单调性。(当然不是所有的最大最小题都能用二分来解决,只是二分对于大部门的这类题目有奇效)
得分越大 => 相邻两个数之间的距离就越远,而范围是固定的,则越难找到满足要求的整数。满足单调性,可以二分,接下来,我们只要考虑 check 函数如何写,即判断一个得分是否能有正当的方案实现 --- 我们可以贪婪的去考虑每一个整数的选取:对于每一个区间,我们尽可能的去区间的左边选数,给背面的区间留下尽可能大的范围去举行选择,看是否每一个区间都能选择出一个数代码如下
  1. class Solution {
  2. public:
  3.     int maxPossibleScore(vector<int>& start, int d) {
  4.         int n = start.size();
  5.         ranges::sort(start);
  6.         auto check = [&](int k)->bool{
  7.             long long pre = start[0]; // 注意:pre可能会超int范围,要用long long
  8.             for(int i = 1; i < n; i++){
  9.                 if(pre + k <= start[i])
  10.                     pre = start[i];
  11.                 else if(pre + k <= start[i] + d)
  12.                     pre += k;
  13.                 else
  14.                     return false;
  15.             }
  16.             return true;
  17.         };
  18.         int l = 0, r = (start.back() + d - start[0]) / (n - 1) + 1;
  19.         while(l <= r){
  20.             int mid = l + (r - l)/2;
  21.             if(check(mid)) l = mid + 1;
  22.             else r = mid - 1;
  23.         }
  24.         return r;
  25.     }
  26. };
复制代码
三、到达数组末了的最大得分


这题很容易让人想到动态规划,状态界说为 dp 以 i 为结尾的最大总得分,dp = max(dp[k]+(i-k)*nums[k]),然后取dp中的最大值返回,时间复杂度为O(n^2),显然是过不了的,而且我们也无法优化,如何做?当我们dp做不出的时候,我们可以取想想贪婪。
那么如何贪婪呢?我们来观察这个式子 (j - i) * nums,我们可以从柱状图的方式去思考这个式子

(j - i) * nums 的本质就是 长 * 宽,即让我们选择尽可能大的nums作为矩阵的边长,让单个矩阵的面积最大,从而让面积之和最大。代码如下
  1. class Solution {
  2.     using LL = long long;
  3. public:
  4.     long long findMaximumScore(vector<int>& nums) {
  5.         int n = nums.size();
  6.         LL ans = 0;
  7.         int mx = 0;
  8.         for(int i = 0; i < n - 1; i++){
  9.             mx = max(mx, nums[i]); // 取前缀最大值 加入 ans
  10.             ans += mx;
  11.         }
  12.         return ans;
  13.     }
  14. };
复制代码
四、吃掉所有兵需要的最多移动步数


思路:首先,我们要预处置处罚得到马在恣意位置到达每个兵的最小步数,这里我们也可以反向考虑,假设马在兵的位置上时,到达恣意位置的最小步数,可以用bfs解决,然后我们就能dfs暴力的枚举Alice和Bob吃哪一个兵能使得个自的策略最优,代码如下
  1. class Solution {
  2.     const int dir[8][2]={-2,-1,-2,1,-1,-2,-1,2,1,-2,1,2,2,-1,2,1};
  3. public:
  4.     int maxMoves(int kx, int ky, vector<vector<int>>& positions) {
  5.         int n = positions.size();
  6.         int f[n][50][50];
  7.         memset(f, -1, sizeof(f));
  8.         for(int i = 0; i < n; i++){
  9.             int x0 = positions[i][0], y0 = positions[i][1];
  10.             queue<pair<int,int>> q;
  11.             q.emplace(x0, y0);
  12.             f[i][x0][y0] = 0;
  13.             while(q.size()){
  14.                 auto [x, y] = q.front(); q.pop();
  15.                 // cout << x << " " << y << endl;
  16.                 for(int j = 0; j < 8; j++){
  17.                     int dx = x + dir[j][0];
  18.                     int dy = y + dir[j][1];
  19.                     if(dx < 0 || dx >= 50 || dy < 0 || dy >= 50 || f[i][dx][dy] >= 0)
  20.                         continue;
  21.                     f[i][dx][dy] = f[i][x][y] + 1;
  22.                     q.emplace(dx, dy);
  23.                 }
  24.             }
  25.         }
  26.         int memo[n][1<<n];
  27.         memset(memo, -1, sizeof(memo));
  28.         function<int(int,int)> dfs = [&](int i, int mask)->int{
  29.             if(mask == (1 << n) - 1) return 0;
  30.             if(memo[i][mask] != -1) return memo[i][mask];
  31.             int cnt0 = __builtin_popcount(mask);
  32.             int res = cnt0 & 1 ? INT_MAX : 0;
  33.             int x0 = positions[i][0], y0 = positions[i][1];
  34.             for(int j = 0; j < n; j++){
  35.                 if(mask >> j & 1) continue;   
  36.                 int x = positions[i][0], y = positions[i][1];
  37.                 if(cnt0 & 1){
  38.                     res = min(res, dfs(j, mask | 1 << j) + f[j][x][y]);
  39.                 }else{
  40.                     res = max(res, dfs(j, mask | 1 << j) + f[j][x][y]);
  41.                 }
  42.             }
  43.             return memo[i][mask] = res;
  44.         };
  45.         int ans = 0;
  46.         for(int i = 0; i < n; i++){
  47.             ans = max(ans, dfs(i, 1 << i) + f[i][kx][ky]);
  48.         }
  49.         return ans;
  50.     }
  51. };
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

温锦文欧普厨电及净水器总代理

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表