力扣第 263 场周赛总结

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,就果断放弃了暴力法,想了半天没有什么好的方法,才回头注意到提示给的范围,下次需要额外小心。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值