力扣春季编程大赛(LCCUP‘21)

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 targetx的个数即可。

时空复杂度

时间:要先排序 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 时,站位如图所示

image.png

请返回位于场地坐标 [Xpos,Ypos] 的成员所持乐器编号。

示例 1:

输入:num = 3, Xpos = 0, Ypos = 2

输出:3

解释:
image.png

示例 2:

输入:num = 4, Xpos = 1, Ypos = 2

输出:5

解释:
image.png

提示:

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 n2f)。这样的话就能够把第 f f f层左上角的数值算出来。目标点所在的 f f f层外面的 f − 1 f-1 f1层共有 q = n 2 − ( n − 2 ∗ f ) 2 q=n^{2}-(n - 2*f)^{2} q=n2(n2f)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;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值