5902. 检查句子中的数字是否递增
句子是由若干 token 组成的一个列表,token 间用 单个 空格分隔,句子没有前导或尾随空格。每个 token 要么是一个由数字 0-9 组成的不含前导零的 正整数 ,要么是一个由小写英文字母组成的 单词 。
示例,“a puppy has 2 eyes 4 legs” 是一个由 7 个 token 组成的句子:“2” 和 “4” 是数字,其他像 “puppy” 这样的 tokens 属于单词。
给你一个表示句子的字符串 s ,你需要检查 s 中的 全部 数字是否从左到右严格递增(即,除了最后一个数字,s 中的 每个 数字都严格小于它 右侧 的数字)。
如果满足题目要求,返回 true ,否则,返回 false 。
Solution
本题描述看起来挺吓人的,但在看完之后就豁然开朗了,只是需要我们将字符串中的数字过滤出来进行,然后判断这些数字序列是不是严格递增的即可。
- 判断字符是否在 ‘0’ ~ ‘9’ 之间
- 如果在 ‘0’ ~ ‘9’ 之间,那么用一个循环将数字字符串转换为整型,比如 (string) “1234” 转换为 (int) 1234,并与之前的数字进行比较,如果是严格单调增(严格单调增:假设有两个数字a、b,那么 a < b 就是对于a b数字序列来说的严格递增),继续遍历;如果不是严格递增的,那么直接返回 false,程序结束。
- 如果不在 ‘0’ ~ ‘9’ 之间,不需要处理,继续遍历即可。
class Solution {
public:
bool areNumbersAscending(string s) {
int n = s.length();
int pre = INT_MIN;
for (int i = 0; i < n; ++i) {
if (s[i] > '0' && s[i] <= '9') {//找到第一个1 ~ 9的数字
int c = 0;
while (i < n && s[i] >= '0' && s[i] <= '9')
c += 10 * c + s[i++] - '0';
if (c > pre)
pre = c;
else
return false;
}
}
return true;
}
};
在遍历之前将用于记录前一个数字值的变量 pre 设置为了 INT_MIN,保证在比较过程中题中字符串出现的第一个数字是大于 pre 的。
- 时间复杂度: 一次遍历,O(N)
- 空间复杂度: 使用常数个变量,O(1)
5903. 简易银行系统
你的任务是为一个很受欢迎的银行设计一款程序,以自动化执行所有传入的交易(转账,存款和取款)。银行共有 n 个账户,编号从 1 到 n 。每个账号的初始余额存储在一个下标从 0 开始的整数数组 balance 中,其中第 (i + 1) 个账户的初始余额是 balance[i] 。
请你执行所有 有效的 交易。如果满足下面全部条件,则交易 有效 :
- 指定的账户数量在 1 和 n 之间,且
- 取款或者转账需要的钱的总数 小于或者等于 账户余额。
输入:
["Bank", "withdraw", "transfer", "deposit", "transfer", "withdraw"]
[[[10, 100, 20, 50, 30]], [3, 10], [5, 1, 20], [5, 20], [3, 4, 15], [10, 50]]
输出:
[null, true, true, true, false, false]
解释:
Bank bank = new Bank([10, 100, 20, 50, 30]);
bank.withdraw(3, 10); // 返回 true ,账户 3 的余额是 $20 ,所以可以取款 $10 。
// 账户 3 余额为 $20 - $10 = $10 。
bank.transfer(5, 1, 20); // 返回 true ,账户 5 的余额是 $30 ,所以可以转账 $20 。
// 账户 5 的余额为 $30 - $20 = $10 ,账户 1 的余额为 $10 + $20 = $30 。
bank.deposit(5, 20); // 返回 true ,可以向账户 5 存款 $20 。
// 账户 5 的余额为 $10 + $20 = $30 。
bank.transfer(3, 4, 15); // 返回 false ,账户 3 的当前余额是 $10 。
// 所以无法转账 $15 。
bank.withdraw(10, 50); // 返回 false ,交易无效,因为账户 10 并不存在。
提示:
- n == balance.length
- 1 <= n, account, account1, account2 <= 10^5
- 0 <= balance[i], money <= 10^12
- transfer, deposit, withdraw 三个函数,每个 最多调用 10^4 次
Solution
本题很简单,题看完之后基本上就明白如何做了,老老实实完成每个函数的实现即可。
class Bank {
public:
using ll = long long;
vector<ll> b;
int n;
Bank(vector<long long>& balance) {
b = balance;
n = b.size();
}
bool transfer(int account1, int account2, long long money) {
if (account1 < 1 || account1 > n || account2 < 1 || account2 > n)
return false;
if (b[account1 - 1] < money)
return false;
b[account1 - 1] -= money;
b[account2 - 1] += money;
return true;
}
bool deposit(int account, long long money) {
if (account < 1 || account > n)
return false;
b[account - 1] += money;
return true;
}
bool withdraw(int account, long long money) {
if (account < 1 || account > n || money > b[account - 1])
return false;
b[account - 1] -= money;
return true;
}
};
5904. 统计按位或能得到最大值的子集数目
给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。
如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。
对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR … OR a[a.length - 1](下标从 0 开始)。
示例 1:
输入:nums = [3,1]
输出:2
解释:子集按位或能得到的最大值是 3 。有 2 个子集按位或可以得到 3 :
- [3]
- [3,1]
示例 2:
输入:nums = [2,2,2]
输出:7
解释:[2,2,2] 的所有非空子集的按位或都可以得到 2 。总共有 23 - 1 = 7 个子集。
示例 3:
提示:
- 1 <= nums.length <= 16
- 1 <= nums[i] <= 10^5
Solution
首先可以通过一次遍历得到nums集合按照位或得到的最大值,这里只需要略懂一点位或的原理就能明白。
再根据数据量 nums.length() <= 16 可以使用暴力法:
class Solution {
public:
int Max = 0;//通过位或运算得到的最大值
int cou = 0;//记录符合条件的子集个数
vector<int> path;//dfs 路径
void check() {//检查path集合的元素位或是否等于Max
if (path.size() < 1)
return;
int c = 0;
for (auto& e : path)
c |= e;
if (c == Max)
++cou;
}
void dfs(vector<int>& nums, int depth, int& n) {//dfs回溯收集所有子集
if (depth >= n) {
check();
return;
}
path.push_back(nums[depth]);
dfs(nums, depth + 1, n);
path.pop_back();
dfs(nums, depth + 1, n);
}
int countMaxOrSubsets(vector<int>& nums) {
//第一遍将所有元素进行位或运算,得到的一定是最大值
int n = nums.size();
for (auto& num : nums) {
Max |= num;
}
dfs(nums, 0, n);
return cou;
}
};
- 时间复杂度: O(2^N), 其中N为 nums 数组的长度
- 空间复杂度: O(N),使用了path数组
总结
本次周赛前三题还是不难的,但是笔者在做第三题时犯了一个致命错误,将提示部分看错了,以为数组元素数量级会到 10 ^ 5,就果断放弃了暴力法,想了半天没有什么好的方法,才回头注意到提示给的范围,下次需要额外小心。