LeetCode 第 298 场周赛

LeetCode 第 298 场周赛

题3搞慢了,以至于没咋看题4。过一眼题4,直接脑补了的切割,以至于就直接 pass 了,明明是送分的

5242.兼具大小写的最好英文字母

题目链接:5242.兼具大小写的最好英文字母

给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的 最好
英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。

最好 英文字母的大写和小写形式必须 s 中出现。

英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中,ba 出现。

示例 Sample

示例 1:


输入: s = "l _ Ee_ TcOd _ E_ "
输出: "E"
解释:
字母 'E' 是唯一一个大写和小写形式都出现的字母。

示例 2:


输入: s = "a _ rR_ AzFif"
输出: "R"
解释:
字母 'R' 是大写和小写形式都出现的最好英文字母。
注意 'A' 和 'F' 的大写和小写形式也都出现了,但是 'R' 比 'F' 和 'A' 更好。

示例 3:


输入: s = "AbCdEfGhIjK"
输出: ""
解释:
不存在大写和小写形式都出现的字母。

提示:

  • 1 <= s.length <= 1000
  • s 由小写和大写英文字母组成

我的题解

class Solution {
 public:
  string greatestLetter(string s) {
    vector<int> c(256, 0);
    for (char ch : s) c[ch] = 1;
    for (char ch = 'Z'; ch >= 'A'; ch--) {
      if (c[ch] != 0 && c[(int)ch - 'A' + 'a'] != 0) {
        return string(1, ch);
      }
    }
    return "";
  }
};

5218.个位数字为 K 的整数之和

题目链接:5218.个位数字为 K 的整数之和

给你两个整数 numk ,考虑具有以下属性的正整数多重集:

  • 每个整数个位数字都是 k
  • 所有整数之和是 num

返回该多重集的最小大小,如果不存在这样的多重集,返回 __-1

注意:

  • 多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0
  • 个位数字 是数字最右边的数位。

示例 Sample

示例 1:


输入: num = 58, k = 9
输出: 2
解释:
多重集 [9,49] 满足题目条件,和为 58 且每个整数的个位数字是 9 。
另一个满足条件的多重集是 [19,39] 。
可以证明 2 是满足题目条件的多重集的最小长度。

示例 2:


输入: num = 37, k = 2
输出: -1
解释: 个位数字为 2 的整数无法相加得到 37 。

示例 3:


输入: num = 0, k = 7
输出: 0
解释: 空多重集的和为 0 。

提示:

  • 0 <= num <= 3000
  • 0 <= k <= 9

我的题解

暴力搞一下, 循环节肯定不大

class Solution {
 public:
  int minimumNumbers(int num, int k) {
    if (num == 0) return 0;
    for (int i = 0, s = 0; i < 10 && s <= num; i++) {
      s += k;
      if (num % 10 == s % 10) return i + 1;
    }
    return -1;
  }
};

6099.小于等于 K 的最长二进制子序列

题目链接:6099.小于等于 K 的最长二进制子序列

给你一个二进制字符串 s 和一个正整数 k

请你返回 s最长 子序列,且该子序列对应的 二进制 数字小于等于 k

注意:

  • 子序列可以有 前导 0
  • 空字符串视为 0
  • 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。

示例 Sample

示例 1:


输入: s = "1001010", k = 5
输出: 5
解释: s 中小于等于 5 的最长子序列是 "00010" ,对应的十进制数字是 2 。
注意 "00100" 和 "00101" 也是可行的最长子序列,十进制分别对应 4 和 5 。
最长子序列的长度为 5 ,所以返回 5 。

示例 2:


输入: s = "00101001", k = 1
输出: 6
解释: "000001" 是 s 中小于等于 1 的最长子序列,对应的十进制数字是 1 。
最长子序列的长度为 6 ,所以返回 6 。

提示:

  • 1 <= s.length <= 1000
  • s[i] 要么是 '0' ,要么是 '1'
  • 1 <= k <= 109

我的题解

枚举首位 1 的位置,然后判断下剩下的要小于k,最长能多少位。

class Solution {
  int gao(const string &s, int l, int r, const vector<int> &v) const {
    if (r - l + 1 < v.size()) return r - l + 1;
    int p = 0, q = l;
    while (p < v.size() && q <= r) {
      if (v[p] + '0' == s[q]) {
        p++, q++;
      } else if (v[p] + '0' > s[q]) {
        p += min((int)v.size() - p, r - q + 1);
        break;
      } else {
        q++;
      }
    }
    int ans = p;
    return ans;
  }

  inline vector<int> parse(int k) const {
    vector<int> v;
    while (k) {
      v.push_back(k & 1);
      k >>= 1;
    }
    reverse(v.begin(), v.end());
    return v;
  }

 public:
  int longestSubsequence(string s, int k) {
    const int n = s.length();
    int ans(0);
    vector<int> c(n, 0);
    for (int i = 0; i < n; i++) c[i] = (i ? c[i - 1] : 0) + (s[i] == '0' ? 1 : 0);
    vector<int> v = parse(k);
    for (int i = 0; i < n; i++) {
      if (s[i] == '1') {
        int x = gao(s, i, n - 1, v);
        ans = max(ans, (i ? c[i - 1] : 0) + x);
      }
    }
    ans = max(ans, c[n - 1]);
    return ans;
  }
};

y总的解法

class Solution {
 public:
  int longestSubsequence(string s, int k) {
    string t;
    while (k) t += to_string(k & 1), k >>= 1;
    reverse(t.begin(), t.end());
    int n = s.length(), m = t.length();
    if (n < m) return n;
    int res = m - 1;
    for (int i = 0; i < n - (m - 1); i++)
      if (s[i] == '0') res++;
    if (s.substr(n - m) <= t) {
      int cnt = 0;
      for (int i = 0; i < n - m; i++) {
        if (s[i] == '0') cnt++;
      }
      res = max(res, cnt + m);
    }
    return res;
  }
};

5254.卖木头块

题目链接:5254.卖木头块

给你两个整数 mn ,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices ,其中 prices[i] = [hi, wi, pricei] 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。

每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:

  • 沿垂直方向按高度 完全 切割木块,或
  • 沿水平方向按宽度 完全 切割木块

在将一块木块切成若干小木块后,你可以根据 prices 卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能
旋转切好后木块的高和宽。

请你返回切割一块大小为 _ _m x n __ 的木块后,能得到的 最多 钱数。

注意你可以切割木块任意次。

示例 Sample

示例 1:


输入: m = 3, n = 5, prices = [[1,4,2],[2,2,7],[2,1,3]]
输出: 19
解释: 上图展示了一个可行的方案。包括:
- 2 块 2 x 2 的小木块,售出 2 * 7 = 14 元。
- 1 块 2 x 1 的小木块,售出 1 * 3 = 3 元。
- 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。
总共售出 14 + 3 + 2 = 19 元。
19 元是最多能得到的钱数。

示例 2:


输入: m = 4, n = 6, prices = [[3,2,10],[1,4,2],[4,1,3]]
输出: 32
解释: 上图展示了一个可行的方案。包括:
- 3 块 3 x 2 的小木块,售出 3 * 10 = 30 元。
- 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。
总共售出 30 + 2 = 32 元。
32 元是最多能得到的钱数。
注意我们不能旋转 1 x 4 的木块来得到 4 x 1 的木块。

提示:

  • 1 <= m, n <= 200
  • 1 <= prices.length <= 2 * 104
  • prices[i].length == 3
  • 1 <= hi <= m
  • 1 <= wi <= n
  • 1 <= pricei <= 106
  • 所有 (hi, wi) 互不相同

我的题解

完全切割,枚举每次切割的位置DP就行。

是不是还能有变种,每次都是在 NxM 的总体上切

class Solution {
 public:
  long long sellingWood(int m, int n, vector<vector<int>> &prices) {
    vector<vector<long long>> f(m + 1, vector<long long>(n + 1));
    for (auto &i : prices) f[i[0]][i[1]] = max(f[i[0]][i[1]], (long long)i[2]);
    for (int i = 1; i <= m; i++) {
      for (int j = 1; j <= n; j++) {
        for (int k = 1; k < i; k++) f[i][j] = max(f[i][j], f[k][j] + f[i - k][j]);
        for (int k = 1; k < j; k++) f[i][j] = max(f[i][j], f[i][k] + f[i][j - k]);
      }
    }
    return f[m][n];
  }
};
posted @ 2022-06-19 13:53  菁芜  阅读(23)  评论(0编辑  收藏  举报