BACKGROUND
本来是要参加团队赛的,我顺手把个人赛也报上了。
FINALLY
排名:469 / 9932
好菜。。。五题做了三题。
说是有企业内推然而并不知道如何操作hh或许我应该先去写个简历。
PROBLEM
1. 采购方案
题目描述
小力将 N 个零件的报价存于数组 nums。小力预算为 target,假定小力仅购买两个零件,要求购买零件的花费不超过预算,请问他有多少种采购方案。
注意:答案需要以 1e9 + 7 (1000000007) 为底取模,如:计算初始结果为:1000000008,请返回 1
示例 1:
输入:nums = [2,5,3,5], target = 6
输出:1
解释:预算内仅能购买 nums[0] 与 nums[2]。
示例 2:
输入:nums = [2,2,1,9], target = 10
输出:4
解释:符合预算的采购方案如下:
nums[0] + nums[1] = 4
nums[0] + nums[2] = 3
nums[1] + nums[2] = 3
nums[2] + nums[3] = 10
提示:
2 <= nums.length <= 10^5
1 <= nums[i], target <= 10^5
解题思路
看了看数据范围,想到二分敲了一下就过了。因为两个数总和不超过 t a r g e t target target,所以对于每个数字 x x x去找小于等于 t a r g e t − x target-x target−x的个数即可。
时空复杂度
时间:要先排序
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),枚举数字
O
(
n
)
O(n)
O(n),二分找小于t的数的个数
O
(
l
o
g
n
)
O(logn)
O(logn),总体时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
n
)
O(n)
O(n)
参考代码
class Solution {
public:
int purchasePlans(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
long long ans = 0;
for (int i = 0 ; i < nums.size(); i ++){
int &x = nums[i];
if (x >= target) break;
int t = target - x;
// 找到<=t 的个数
int p = upper_bound(nums.begin(),nums.end(), t) - nums.begin() - i;
if (x <= t) p --;
if (p <= 0) continue;
// printf("%d : %d\n", x , p);
ans = (ans + p) % 1000000007;
}
return ans;
}
};
2. 乐团站位
题目描述
某乐团的演出场地可视作 num * num 的二维矩阵 grid(左上角坐标为 [0,0]),每个位置站有一位成员。乐团共有 9 种乐器,乐器编号为 1~9,每位成员持有 1 个乐器。
为保证声乐混合效果,成员站位规则为:自 grid 左上角开始顺时针螺旋形向内循环以 1,2,…,9 循环重复排列。例如当 num = 5 时,站位如图所示
请返回位于场地坐标 [Xpos,Ypos] 的成员所持乐器编号。
示例 1:
输入:num = 3, Xpos = 0, Ypos = 2
输出:3
解释:
示例 2:
输入:num = 4, Xpos = 1, Ypos = 2
输出:5
解释:
提示:
1 <= num <= 10^9
0 <= Xpos, Ypos < num
解题思路
当时想了一会儿没啥思路然后就去做C,做完C再回来推这个。我先把目标点的层数计算出来(一共就有
n
+
1
2
\frac{n + 1}{2}
2n+1层,规定最外面一圈是第0层,里面一圈是第1层…所以第
f
f
f层的边长是
n
−
2
∗
f
n - 2 * f
n−2∗f)。这样的话就能够把第
f
f
f层左上角的数值算出来。目标点所在的
f
f
f层外面的
f
−
1
f-1
f−1层共有
q
=
n
2
−
(
n
−
2
∗
f
)
2
q=n^{2}-(n - 2*f)^{2}
q=n2−(n−2∗f)2个单位(大的正方形减去小的正方形),所以第
f
f
f层左上角的那个数值就是
k
=
(
q
+
1
)
%
9
k = (q + 1 )\% 9
k=(q+1)%9。然后定位目标点在
f
f
f层的位置(上下左右),得出结果。
时空复杂度
数学做法,时空均为 O ( 1 ) O(1) O(1)
参考代码
class Solution {
public:
int orchestraLayout(int num, int xPos, int yPos) {
const int INF = 1e9 + 7;
int f = INF;
f = min(f, xPos);f = min(f, yPos);
// printf("%d", xPos);
f = min(f, num - xPos - 1);f = min(f, num - yPos - 1);
// 在第f层上
long long q = 4ll * f * (num - f);
q = (q + 1) % 9;
// 第f层左上角的位置
xPos -= f, yPos -= f;
// printf("%d %d\n", xPos, yPos);
// 第f层每一边长度为n - 2f
int sz = num - 2 * f - 1;
// printf("sz : %d\n", sz);
if (xPos == 0){
// printf("q : %d\n", q);
q = (q + yPos) % 9;
// 第一行的情况
// printf("1");
}else if (yPos == sz){
q += sz;
q += (xPos);
q %= 9;
// 右边一列的情况
// printf("2");
}else if (xPos == sz){
q += sz + sz;
q += (sz - yPos);
q %= 9;
// printf("3");
}else{
q += sz + sz + sz;
q += (sz - xPos);
q %= 9;
// printf("4");
}
if (q == 0) q = 9;
return q;
}
};
3. 魔塔游戏
题目描述
小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0 表示房间对血量无影响。
小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。
示例 1:
输入:nums = [100,100,100,-250,-60,-140,-50,-50,100,150]
输出:1
解释:初始血量为 1。至少需要将 nums[3] 调整至访问顺序末尾以满足要求。
示例 2:
输入:nums = [-200,-300,400,0]
输出:-1
解释:调整访问顺序也无法完成全部房间的访问。
提示:
1 <= nums.length <= 10^5
-10^5 <= nums[i] <= 10^5
解题思路
猜了一个贪心结论然后过了。首先全部的和如果小于0的话英雄是必死的;其次,每次当英雄要死的时候,我就把此前最大的BOSS“删除”,这样英雄就能活下来了!找最大值用优先队列维护即可。
时空复杂度
优先队列维护局部最大值,时间为 O ( n l o g n ) O(nlogn) O(nlogn),空间为 O ( n ) O(n) O(n)
参考代码
class Solution {
public:
int magicTower(vector<int>& nums) {
long long s = 1;
long long d = 0;
long long tp = 1;
int a = 0;
priority_queue<int, vector<int>, greater<>> q;
for (auto &x : nums){
tp += x;
if (x >= 0) s += x;
else{
d -= x;
q.push(x);
if (s <= d){
a ++;
int t = q.top();
d += t;
q.pop();
// printf("%d %d\n",t, d);
}
}
}
if (tp <= 0) return -1;
return a;
}
};