2309. 兼具大小写的最好英文字母
给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的 最好 英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。
最好 英文字母的大写和小写形式必须 都 在 s 中出现。
英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中,b 在 a 之 后 出现。
示例 1:
输入:s = “lEeTcOdE”
输出:“E”
解释:
字母 ‘E’ 是唯一一个大写和小写形式都出现的字母。
示例 2:
输入:s = “arRAzFif”
输出:“R”
解释:
字母 ‘R’ 是大写和小写形式都出现的最好英文字母。
注意 ‘A’ 和 ‘F’ 的大写和小写形式也都出现了,但是 ‘R’ 比 ‘F’ 和 ‘A’ 更好。
示例 3:
输入:s = “AbCdEfGhIjK”
输出:“”
解释:
不存在大写和小写形式都出现的字母。
提示:
1 <= s.length <= 1000
s 由小写和大写英文字母组成
思路
遍历一遍字符串,只要是字母就标记,之后遍历标记数组,从后往前判断,大小写都有的,第一个符合的也是最大的
代码
class Solution {
public:
int t[100];
string greatestLetter(string s) {
string res = "";
for (int i = 0; i < s.size(); i++) {
t[s[i] - 'A'] = 1;
}
for (int i = 0; i < 26; i++) {
if (t[i] == 1 && t[i + 32] == 1) {
res = i + 'A';
}
}
return res;
}
};
2310. 个位数字为 K 的整数之和
给你两个整数 num 和 k ,考虑具有以下属性的正整数多重集:
每个整数个位数字都是 k 。
所有整数之和是 num 。
返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。
注意:
多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。
个位数字 是数字最右边的数位。
示例 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
贪心
拆解,nk + 10t == num
(num - nk) % 10 == 0
class Solution {
public:
int minimumNumbers(int num, int k) {
if (num == 0) return 0;
// 拆解,nk + 10t == num
// (num - nk) % 10 == 0
for (int i = 1; i <= num && num - k * i >= 0; i++) {
if ((num - k * i) % 10 == 0) {
return i; // 因为是从小到大模拟的,第一个遇到的合适的条件就是最小值
}
}
return -1;
}
};
动态规划1
当num == 0 时,返回0,如果k是偶数,但是num是奇数,直接返回-1,不可能
先挑选出来个位是k的数,组成一个数组,作为背包,然后一维滚动数组,动态规划
外层遍历物品,内层遍历背包容量
初始化,dp[0] = 0,因为num是0的时候,由0个数字组成,要取组成num的数的个数的最小值,所以数组初始化为无穷大
dp[j] = min(dp[j - i] + 1, dp[j]),要么就取j-i的数量 + 1,要么就取 dp[j]
class Solution {
public:
int bg[3010];
int dp[3010];
int minimumNumbers(int num, int k) {
if (num == 0) return 0;
if (num % 2 == 1 && k % 2 == 0) return -1;
int cnt = 0;
for (int i = 1; i <= num; i++) {
if (i % 10 == k) bg[cnt++] = i;
}
for (int i = 1; i <= num; i++) dp[i] = 99999;
dp[0] = 0;
for (int i = 0; i < cnt; i++) {
for (int j = bg[i]; j <= num; j++) {
dp[j] = min(dp[j - bg[i]] + 1, dp[j]);
}
}
if (dp[num] == 99999) return -1;
return dp[num];
}
};
动态规划2
class Solution {
int dp[3001];
public:
int minimumNumbers(int num, int k) {
memset(dp, 127, sizeof(dp)); // 求最小,初始无穷大
dp[0] = 0;
for (int i = 0; i <= num; i++) {
for (int j = i; j <= num; j++) {
if (i % 10 == k)
dp[j] = min(dp[j - i] + 1, dp[j]);
}
}
if (dp[num] > 1 << 30) return -1;
return dp[num];
}
};
2311. 小于等于 K 的最长二进制子序列
给你一个二进制字符串 s 和一个正整数 k 。
请你返回 s 的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k 。
注意:
子序列可以有 前导 0 。
空字符串视为 0 。
子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。
示例 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
贪心?
设置一个bool数组初始化为 false
因为可以有前导0,所以先把所有的零都选上,ans记录一下现在的个数
然后,因为1在右边加的少,在左边加的太多了,所以从右往左加,看看这个1加上之后会不会超
class Solution {
bool b[1001];
public:
bool check(string &s, int k) {
int n = s.size(), x = 0;
for (int i = 1; i <= n; i++) {
if (b[i])
x = x * 2 + s[i - 1] - '0';
if (x > k)
return false;
}
return true;
}
int longestSubsequence(string s, int k) {
memset(b, false, sizeof(b));
int n = s.size();
int ans = 0; // 记录数字的个数
for (int i = 1; i <= n; i++) { // 首先,加上所有的 0
if (s[i - 1] == '0')
++ans, b[i] = true; // 记录当前数字的个数,并且把选中的数字改成 true
}
for (int i = n; i > 0; i--)
if (!b[i]) { // 从后往前遍历,将刚才没有加进去的 1
b[i] = true; // 先变成true,方便下面计算
if (!check(s, k)) // 如果超了,就去掉
b[i] = false;
else // 没有超就++
++ans;
}
return ans;
}
};