LeetCode第 123 场双周赛个人题解

目录

一、100222. 三角形类型 II

1、原题链接

2、题目描述

3、思路分析

4、代码详解

二、100194. 人员站位的方案数 I

1、原题链接

2、题目描述

3、思路分析

4、代码详解

三、100183. 最大好子数组和

1、原题链接

2、题目描述

3、思路分析

4、代码详解

四、100193. 人员站位的方案数 II

1、原题链接

2、题目描述

3、思路分析

4、代码详解


一、100222. 三角形类型 II

1、原题链接

三角形类型 II - 力扣 (LeetCode) 竞赛

2、题目描述

给你一个下标从 0 开始长度为 3 的整数数组 nums ,需要用它们来构造三角形。

  • 如果一个三角形的所有边长度相等,那么这个三角形称为 equilateral 。
  • 如果一个三角形恰好有两条边长度相等,那么这个三角形称为 isosceles 。
  • 如果一个三角形三条边的长度互不相同,那么这个三角形称为 scalene 。

如果这个数组无法构成一个三角形,请你返回字符串 "none" ,否则返回一个字符串表示这个三角形的类型。

3、思路分析

签到题,没什么说的

复制的时候多了个空格,喜提WA

时间复杂度:O(1) 空间复杂度:O(1)

4、代码详解

class Solution:
    def triangleType(self, nums: List[int]) -> str:
        a, b, c = nums[0], nums[1], nums[2]
        if a + b > c and a + c > b and b + c > a:
            if a == b == c:
                return "equilateral"
            if a == b or a == c or b == c:
                return "isosceles"
            return "scalene"
        else:
            return "none"

二、100194. 人员站位的方案数 I

1、原题链接

人员站位的方案数 I - 力扣 (LeetCode) 竞赛

2、题目描述

给你一个  n x 2 的二维数组 points ,它表示二维平面上的一些点坐标,其中 points[i] = [xi, yi] 。

我们定义 x 轴的正方向为  (x 轴递增的方向),x 轴的负方向为  (x 轴递减的方向)。类似的,我们定义 y 轴的正方向为  (y 轴递增的方向),y 轴的负方向为  (y 轴递减的方向)。

你需要安排这 n 个人的站位,这 n 个人中包括 liupengsay 和小羊肖恩 。你需要确保每个点处 恰好 有 一个 人。同时,liupengsay 想跟小羊肖恩单独玩耍,所以 liupengsay 会以 liupengsay 的坐标为 左上角 ,小羊肖恩的坐标为 右下角 建立一个矩形的围栏(注意,围栏可能  包含任何区域,也就是说围栏可能是一条线段)。如果围栏的 内部 或者 边缘 上有任何其他人,liupengsay 都会难过。

请你在确保 liupengsay 不会 难过的前提下,返回 liupengsay 和小羊肖恩可以选择的 点对 数目。

注意,liupengsay 建立的围栏必须确保 liupengsay 的位置是矩形的左上角,小羊肖恩的位置是矩形的右下角。比方说,以 (1, 1) ,(1, 3) ,(3, 1) 和 (3, 3) 为矩形的四个角,给定下图的两个输入,liupengsay 都不能建立围栏,原因如下:

  • 图一中,liupengsay 在 (3, 3) 且小羊肖恩在 (1, 1) ,liupengsay 的位置不是左上角且小羊肖恩的位置不是右下角。
  • 图二中,liupengsay 在 (1, 3) 且小羊肖恩在 (1, 1) ,小羊肖恩的位置不是在围栏的右下角。

3、思路分析

二维偏序问题

他这个坐标太烦人了,我把它转了一下

将坐标转换为以左上角为源点,x轴往下延伸,y轴往右延伸

这样有什么好处呢?我们按x坐标升序排序,x相同就按y升序排序

然后我们遍历坐标数组,每个元素右边的所有满足纵坐标大于自己的坐标都有机会配对,因为排序后x坐标已经满足了,只用看y坐标

那么对于那些可能的坐标如何进一步判断配对呢?只要二者围成的区域内没有别的点即可

这个时候我们坐标变换的好处就体现出来了,我们可以通过二维前缀和来判断区域内是否有别的点(不变换也能求前缀和,但是容易写错)

只要区域和为2(即只有配对的两个点),我们答案计数+1

时间复杂度:O(N^2) 空间复杂度:O(U^2),U为坐标最大值

4、代码详解

class Solution
{
public:
    typedef vector<int> vi;
    int g[55][55];
    int numberOfPairs(vector<vector<int>> &p)
    {
        memset(g, 0, sizeof(g));
        int ret = 0, n = p.size();
        for (auto &x : p){
            int a = x[0] + 1, b = x[1] + 1;
            g[x[0] = 52 - b][x[1] = a] = 1;
        }
        sort(p.begin(), p.end(), [&](vi &x, vi &y)
             {
            if(x[0] != y[0])
                return x[0] < y[0];
            return x[1] < y[1]; });

        for (int i = 1; i <= 51; i++)
            for (int j = 1; j <= 51; j++)
                g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
        for (int i = 0; i < n; i++)
        {
            int a = p[i][0], b = p[i][1];
            for (int j = i + 1; j < n; j++)
            {
                int x = p[j][0], y = p[j][1];
                if (y >= b && g[x][y] - g[x][b - 1] - g[a - 1][y] + g[a - 1][b - 1] == 2)
                    ret++;
            }
        }
        return ret;
    }
};

三、100183. 最大好子数组和

1、原题链接

最大好子数组和 - 力扣 (LeetCode) 竞赛

2、题目描述

给你一个长度为 n 的数组 nums 和一个  整数 k 。

如果 nums 的一个子数组中,第一个元素和最后一个元素 差的绝对值恰好 为 k ,我们称这个子数组为  的。换句话说,如果子数组 nums[i..j] 满足 |nums[i] - nums[j]| == k ,那么它是一个好子数组。

请你返回 nums 中  子数组的 最大 和,如果没有好子数组,返回 0 。

3、思路分析

一眼哈希,我们预处理前缀和pre[],开一个哈希表记录每个数字上一次最小前缀出现位置

我们遍历数组,对于nums[i],如果前面出现过nums[i] - k 或者nums[i] + k,那么我们就维护好子数组和最大值

然后就要维护nums[i]在哈希表中存储的下标了

如果哈希表中没有nums[i],直接插入

如果已经存在hash[nums[i]] = j,如果pre[i] < pre[j],我们就将j替换为i

时间复杂度:O(N) 空间复杂度:O(N)

4、代码详解

class Solution
{
public:
    long long maximumSubarraySum(vector<int> &nums, int k)
    {
        int n = nums.size();
        unordered_map<int, int> mp;
        vector<long long> pre(n + 1);
        for (int i = 1; i <= n; i++)
            pre[i] = pre[i - 1] + nums[i - 1];
        long long ret = -1e15;
        for (int i = 0; i < n; i++)
        {
            if (mp.count(nums[i] - k))
            {
                ret = max(ret, pre[i + 1] - pre[mp[nums[i] - k]]);
            }
            if (mp.count(k + nums[i]))
            {
                ret = max(ret, pre[i + 1] - pre[mp[k + nums[i]]]);
            }

            if (!mp.count(nums[i]))
                mp[nums[i]] = i;
            else if(pre[i] < pre[mp[nums[i]]]) mp[nums[i]] = i;
        }
        return ret == -1e15 ? 0 : ret;
    }
};

四、100193. 人员站位的方案数 II

1、原题链接

人员站位的方案数 II - 力扣 (LeetCode) 竞赛

2、题目描述

给你一个  n x 2 的二维数组 points ,它表示二维平面上的一些点坐标,其中 points[i] = [xi, yi] 。

我们定义 x 轴的正方向为  (x 轴递增的方向),x 轴的负方向为  (x 轴递减的方向)。类似的,我们定义 y 轴的正方向为  (y 轴递增的方向),y 轴的负方向为  (y 轴递减的方向)。

你需要安排这 n 个人的站位,这 n 个人中包括 liupengsay 和小羊肖恩 。你需要确保每个点处 恰好 有 一个 人。同时,liupengsay 想跟小羊肖恩单独玩耍,所以 liupengsay 会以 liupengsay 的坐标为 左上角 ,小羊肖恩的坐标为 右下角 建立一个矩形的围栏(注意,围栏可能  包含任何区域,也就是说围栏可能是一条线段)。如果围栏的 内部 或者 边缘 上有任何其他人,liupengsay 都会难过。

请你在确保 liupengsay 不会 难过的前提下,返回 liupengsay 和小羊肖恩可以选择的 点对 数目。

注意,liupengsay 建立的围栏必须确保 liupengsay 的位置是矩形的左上角,小羊肖恩的位置是矩形的右下角。比方说,以 (1, 1) ,(1, 3) ,(3, 1) 和 (3, 3) 为矩形的四个角,给定下图的两个输入,liupengsay 都不能建立围栏,原因如下:

  • 图一中,liupengsay 在 (3, 3) 且小羊肖恩在 (1, 1) ,liupengsay 的位置不是左上角且小羊肖恩的位置不是右下角。
  • 图二中,liupengsay 在 (1, 3) 且小羊肖恩在 (1, 1) ,小羊肖恩的位置不是在围栏的右下角。

3、思路分析

第二题我们的做法是O(N^2)的时间复杂度,本题1e3的数据量照样能过

但是由于这次坐标范围太大了,所以我们要对坐标进行离散化,其它操作一样

时间复杂度:O(N^2) 空间复杂度:O(U^2),U为坐标最大值

4、代码详解

class Solution
{
public:
    typedef vector<int> vi;
    int g[1010][1010], ax[1010], ay[1010], nx, ny;
    int numberOfPairs(vector<vector<int>> &p)
    {
        memset(g, 0, sizeof(g));
        int ret = 0, n = p.size();
        for (int i = 0; i < n; i++)
            ax[i] = p[i][0], ay[i] = p[i][1];
        sort(ax, ax + n), sort(ay, ay + n);
        nx = unique(ax, ax + n) - ax, ny = unique(ay, ay + n) - ay;
        for (auto &x : p)
        {
            int a = lower_bound(ax, ax + nx, x[0]) - ax + 1, b = lower_bound(ay, ay + ny, x[1]) - ay + 1;
            g[x[0] = 1005 - b][x[1] = a] = 1;
        }
        sort(p.begin(), p.end(), [&](vi &x, vi &y)
             {
            if(x[0] != y[0])
                return x[0] < y[0];
            return x[1] < y[1]; });

        for (int i = 1; i <= 1005; i++)
            for (int j = 1; j <= 1005; j++)
                g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
        for (int i = 0; i < n; i++)
        {
            int a = p[i][0], b = p[i][1];
            for (int j = i + 1; j < n; j++)
            {
                int x = p[j][0], y = p[j][1];
                if (y >= b && g[x][y] - g[x][b - 1] - g[a - 1][y] + g[a - 1][b - 1] == 2)
                    ret++;
            }
        }
        return ret;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

EQUINOX1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值