2023.1.7LeetCode第95场双周赛
2525. 根据规则将箱子分类
思路
根据题意模拟即可
代码
class Solution {
public:
string categorizeBox(int a, int b, int c, int m) {
bool f1 = false, f2 = false;
long long t = (long long)a * b * c;
if (a >= 1e4 || b >= 1e4 || c >= 1e4 || t >= 1e9)
f1 = true;
if (m >= 100)
f2 = true;
if (f1 && f2) return "Both";
else if (!f1 && !f2) return "Neither";
else if (f1 && !f2) return "Bulky";
else return "Heavy";
}
};
2526. 找到数据流中的连续整数
思路
使用一个变量记录连续为value的个数,该数量大于等于k说明最后k为数均为value
代码
class DataStream {
public:
int v, k, c;
DataStream(int value, int _k) {
v = value;
k = _k;
c = 0;
}
bool consec(int num) {
if (num == v) c ++ ;
else c = 0;
return c >= k;
}
};
/**
* Your DataStream object will be instantiated and called as such:
* DataStream* obj = new DataStream(value, k);
* bool param_1 = obj->consec(num);
*/
2527. 查询数组 Xor 美丽值
思路
目的:任意i,j,k
,求(nums[i] | nums[j]) & nums[k]
的值
利用位运算的性质:a | b = b | a
,a ^ a = 0
,a | a = a
,a & a = a
故i != j
时,(nums[i] | nums[j]) & nums[k] = (nums[j] | nums[i]) & nums[k]
,两个值异或结果为0,所有i != j
的值两两配对后为0消掉
因此只用考虑i = j
,(nums[i] | nums[i]) & nums[k] = nums[i] & nums[k]
,同时当i != k
时,可以和(nums[k] | nums[k]) & nums[i] = nums[k] & nums[i]
,进行两两配对,结果为0
故只剩下i = j = k
的情况,(nums[i] | nums[i]) & nums[i] = nums[i] & nums[i] = nums[i]
,最后答案为所有值异或结果
代码
class Solution {
public:
int xorBeauty(vector<int>& nums) {
int a = 0;
for (int i : nums) a ^= i;
return a;
}
};
2528. 最大化城市的最小供电站数目
思路
二分+差分
可建造的供电站数量一定,最终电量越小越容易满足,越大越不能满足,具有二分性
二分的时间复杂度为O(logn)
,故需要在O(n)
的时间内check,每次检查能否满足时需要给一段连续区间加上一个数,后面还需继续查询,考虑差分或者树状数组算法,但树状数组时间复杂度为O(nlogn)
,可能会被卡常数,故使用差分来check
此题为从左到右连续查询,需要边累加边计算原数组,即查询
动态查询则只能用树状数组
代码
typedef long long ll;
class Solution {
public:
int n;
long long maxPower(vector<int>& num, int m, int k) {
n = num.size();
vector<ll> s(n + 1); //前缀和数组
vector<ll> a(n); //初始状态的电量
for (int i = 0; i < n; i ++ ) s[i + 1] = s[i] + num[i];
for (int i = 0; i < n; i ++ ) {
int l = max(1, i - m + 1), r = min(i + m + 1, n);
a[i] = s[r] - s[l - 1];
}
vector<ll> b(n + 2); //差分数组
for (int i = 0; i < n; i ++ ) {
if (i) b[i + 1] = a[i] - a[i - 1];
else b[i + 1] = a[i];
}
ll l = 0, r = 1e18;
while (l < r) {
ll mid = l + r + 1 >> 1;
if (check(mid, b, k, m)) l = mid;
else r = mid - 1;
}
return l;
}
bool check(ll x, vector<ll> b, ll k, int m) { //x为每座城市要达到的电量,b是差分数组,k是可建造的数量,m是半径
for (int i = 1; i <= n; i ++ ) {
b[i] += b[i - 1]; //每次累加得出当前电量
ll cur = b[i]; //第i座城市的电量
if (cur < x) {
ll t = x - cur;
if (k < t) return false; //可建造的数量不足
k -= t;
int l = i, r = min(n, i + m * 2);
b[r + 1] -= t;
b[l] += t;
}
}
return true;
}
};
附:树状数组(tle)
区间修改,单点查询
typedef long long ll;
class Solution {
public:
int n;
long long maxPower(vector<int>& num, int m, int k) {
n = num.size();
vector<ll> s(n + 1);
vector<ll> a(n);
for (int i = 0; i < n; i ++ ) s[i + 1] = s[i] + num[i];
for (int i = 0; i < n; i ++ ) {
int l = max(1, i - m + 1), r = min(i + m + 1, n);
a[i] = s[r] - s[l - 1];
}
ll l = 0, r = 1e18;
while (l < r) {
ll mid = l + r + 1 >> 1;
if (check(mid, a, k, m)) l = mid;
else r = mid - 1;
}
return l;
}
vector<ll> tree;
int lowbit(int x) {
return x & -x;
}
void ins(int p, ll x) {
for (int i = p; i <= n; i += lowbit(i))
tree[i] += x;
}
void update(int x, int y, ll v) {
ins(x, v), ins(y + 1, -v);
}
ll query(int x) {
ll res = 0;
for (int i = x; i > 0; i -= lowbit(i))
res += tree[i];
return res;
}
bool check(ll x, vector<ll> a, ll k, int m) {
tree.clear(); //注意每次清空
tree.resize(n + 1, 0);
for (int i = 1; i <= n; i ++ ) {
update(i, i, a[i - 1]);
}
for (int i = 1; i <= n; i ++ ) {
ll cur = query(i);
if (cur < x) {
ll t = x - cur;
if (k < t) return false;
k -= t;
int l = i, r = min(n, i + m * 2);
update(l, r, t);
}
}
return true;
}
};
树状数组也可以解决单点修改,区间查询的问题