LeetCode: 1395. 统计作战单位数

news2024/12/24 9:41:23

目录

1. 解法一:枚举中点

2. 解法二:树状数组 + 离散化 优化解法一


原题链接:1395. 统计作战单位数 - 力扣(LeetCode)

题目描述:

n 名士兵站成一排。每个士兵都有一个 独一无二 的评分 rating 。

每 3 个士兵可以组成一个作战单位,分组规则如下:

  • 从队伍中选出下标分别为 ijk 的 3 名士兵,他们的评分分别为 rating[i]rating[j]rating[k]
  • 作战单位需满足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中  0 <= i < j < k < n

请你返回按上述条件可以组建的作战单位数量。每个士兵都可以是多个作战单位的一部分。

示例 1:

输入:rating = [2,5,3,4,1]
输出:3
解释:我们可以组建三个作战单位 (2,3,4)、(5,4,1)、(5,3,1) 。

示例 2:

输入:rating = [2,1,3]
输出:0
解释:根据题目条件,我们无法组建作战单位。

示例 3:

输入:rating = [1,2,3,4]
输出:4

提示:

  • n == rating.length
  • 3 <= n <= 1000
  • 1 <= rating[i] <= 10^5
  • rating 中的元素都是唯一的

1. 解法一:枚举中点

要找到有多少个满足条件的三元组,我们可以枚举三元组的中间位置,通过统计中间位置两侧满足条件的元素的数量来解决这个问题。

对于满足条件的三元组有以下两种可能:

1:随着下标的增长,三元组严格递增。在枚举中间位置时,我们就需要统计出中间位置左侧比中间位置元素小的元素个数,再统计出中间位置右侧比中间位置大的元素个数。两者的乘积就是这个中间位置,三元组严格递增的数目。

例如:2,1,3,5,4  当我们枚举到 3 时,统计 3 的左侧小于 3 的元素个数:2,  统计 3 的右侧大于 3 的元素个数:2。那么,以 3 为中间位置,严格递增的三元组数目就是 2 * 2 = 4 (一个简单的组合问题)。

2:随着下标的增长,三元组严格递减。原理和上面是一样的哇!我们需要统计出中间位置左侧比中间位置元素大的元素个数,再统计出中间位置右侧比中间位置小的元素个数。两者的乘积就是这个中间位置,三元组严格递减的数目。

例如:6,5,3,4,2  当我们枚举到 3 时,统计 3 的左侧大于 3 的元素个数:2,  统计 3 的右侧小于 3 的元素个数:1。那么,以 3 为中间位置,严格递减的三元组数目就是 2 * 1 = 2 (一个简单的组合问题)。

重复上述操作,枚举数组中的所有可能的中间位置,计算每个位置的满足条件的三元组个数,求和即可!

 

class Solution {
public:
    int numTeams(vector<int>& rating) {
        int n = rating.size();
        int ans = 0;
        for (int j = 1; j < n - 1; ++j) {
            //左侧小于      左侧大于
            int iless = 0, imore = 0;
            //右侧小于      右侧大于
            int kless = 0, kmore = 0;
            for (int i = 0; i < j; ++i) {
                if (rating[i] < rating[j]) {
                    ++iless;
                }
                else if (rating[i] > rating[j]) {
                    ++imore;
                }
            }
            for (int k = j + 1; k < n; ++k) {
                if (rating[k] < rating[j]) {
                    ++kless;
                }
                else if (rating[k] > rating[j]) {
                    ++kmore;
                }
            }
            ans += iless * kmore + imore * kless;
        }
        return ans;
    }
};

时间复杂度分析:我们在枚举中间位置的时候需要向左和向右遍历数组找到较大和较小元素的个数。因此时间复杂度是:O(N * N)。空间复杂度: O(1)。

2. 解法二:树状数组 + 离散化 优化解法一

在解法二中,我们枚举每个中间位置时,都需要向左和向右找比中间位置大和小的元素个数。这个过程能否优化呢?

我们可以创建一个数组arr, 初始化为0,遍历到一个数字num,就让arr[num] = 1。
如上图:我们遍历到 3 时 2,5,已经出现过了,那么arr[2] 和 arr[5] 就是 1, 
我们要找左侧比 3 小的元素,只需要知道下标为 3 的位置的前缀和即可(如图可知前缀和为1)
我们要找左侧比 3 大的元素,只需要知道整个数组的前缀和(如图可知前缀和为2),然后减去下标为 3 的位置的前缀和(如图可知前缀和为 1 ) 即可:2 - 1 = 1。
计算出结果之后,再让 arr[3] = 1, 代表 3 出现过了!
通过这样的方法我们就可以在较快时间内求出,左侧较小的元素个数,左侧较大的元素个数。

求左侧较小元素的个数与左侧较大元素的个数需要从左向右遍历原数组,求右侧较小元素的个数与右侧较大元素的个数就需要从右向左遍历原数组啦! 

这里的这个 arr 数组如果用普通的前缀和数组,时间复杂度还是没有变,因为我们需要添加新的数到前缀和数组。涉及到单点更新的前缀和维护自然就是树状数组啦!

我们还注意到,原数组的大小只有 1000,但是数组中的元素大小有 10^5 级别的,因此我们可以考虑使用整数的离散化,减小树状数组的高度,优化单点修改和区间查询的效率。

整数保序的离散化(C/C++)_c++离散化-CSDN博客

这是离散化的讲解,树状数组与线段树还没写!如果不熟悉可以用其他大佬的博客复习复习。

 

const int N = 1010; //离散化之后的最大数据范围
int tr[N]; //树状数组
class Solution {
public:
    //树状数组的三个函数
    int lowbit(int x)
    {
        return x & -x;
    }
    //这道题目的add仅仅是加一,就不用多谢一个参数啦
    void add(int x)
    {
        for(int i = x; i <= N; i += lowbit(i))
            tr[i] += 1;
    }

    int query(int x)
    {
        int res = 0;
        for(int i = x; i > 0; i -= lowbit(i))
            res += tr[i];
        return res;
    }
    //离散化需要用到的二分查找,有库函数我不用,唉就是玩儿
    int BinarySearch(vector<int>& nums, int target)
    {
        int l = 0, r = nums.size() - 1;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(nums[mid] < target) l = mid + 1;
            else if(nums[mid] > target) r = mid - 1;
            else return mid + 1;
        }
        return -1;
    }

    int numTeams(vector<int>& rating) {
        int n = rating.size();
        //copy数组用来离散化
        vector<int> copy(rating);
        //题目说了没有重复元素,不需要去重
        sort(copy.begin(), copy.end());
        //记录左右两侧较大和较小的元素个数
        vector<int> iless(n);
        vector<int> ibig(n);
        vector<int> kless(n);
        vector<int> kbig(n);
        
        int index = 0;
        //初始化树状数组
        memset(tr, 0, sizeof tr);
        //从前向后遍历找左侧
        for(int i = 0; i < n; i++)
        {
            //查找离散化之后的结果
            index = BinarySearch(copy, rating[i]);
            //左侧较小
            iless[i] = query(index);
            //右侧较大
            ibig[i] = query(1000) - query(index);
            //加入新的数
            add(index);
        }
        //初始化
        memset(tr, 0, sizeof tr);
        //从后往前遍历找右侧
        for(int i = n - 1; i >= 0; i--)
        {
            //同上
            index = BinarySearch(copy, rating[i]);
            kless[i] = query(index);
            kbig[i] = query(1000) - query(index);
            add(index);
        }
        //计算结果!
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            ans += iless[i] * kbig[i] + ibig[i] * kless[i];
        }
        return ans;
    }
};

 时间复杂度分析:树状数组单点修改与区间查询的时间复杂度都是 O(logN), 因此最终的时间复杂度:O(N*logN),空间复杂度:O(N).

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1085169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JWT】快速了解什么是jwt及如何使用jwt

一、导言 1、什么是jwt及组成部分 JWT&#xff08;JSON Web Token&#xff09;是一种用于在网络应用间安全传递声明&#xff08;claim&#xff09;的开放标准。它由三部分组成&#xff1a;头部&#xff08;Header&#xff09;、载荷&#xff08;Payload&#xff09;和签名&…

ARM 按键控制 LED灯,蜂鸣器,风扇

main.c: #include "uart.h" #include "key_it.h" int main() {all_led_init();uart4_init();//串口初始化//中断初始化key_it_config();key3_it_config();buzzer_init();fan_init();while(1){//保证主程序不结束}return 0; }src/key_it.c: #include"…

嵌入式面试常见问题(一)

目录 1.什么情况下会出现段错误&#xff1f; 2.swap() 函数为什么不能交换两个变量的值 3.一个函数有六个参数 分别放在哪个区&#xff1f; 4.定义一个变量&#xff0c;赋初值和不赋初值分别保存在哪个区&#xff1f; 5.linux查看端口状态的命令 6.结构体中->和.的区…

简单多状态dp【动态规划】

目录 一、按摩师 二、打家劫舍 三、删除并获得点数 四、粉刷房子 五、买卖股票的最佳时机 六、买卖股票的最佳时机&#xff08;含手续费&#xff09; 七、买卖股票的最佳时机III 八、买卖股票的最佳时机IV 一、按摩师 class Solution { public:int massage(vector<int>…

Avalonia如何更改全局背景色

1.项目下载地址&#xff1a;https://gitee.com/confusedkitten/avalonia-demo 2.UI库Semi.Avalonia&#xff0c;项目地址 https://github.com/irihitech/Semi.Avalonia 3.ColorView&#xff0c;使用Semi.Avalonia.ColorPicker&#xff0c;Nuget获取就行 4.样式预览 以下是…

MyCat实战

概念介绍 在 MyCat 的整体结构中&#xff0c;分为两个部分&#xff1a;上面的逻辑结构、下面的物理结构。 在 MyCat 的逻辑结构主要负责逻辑库、逻辑表、分片规则、分片节点等逻辑结构的处理&#xff0c;而具体的数据存储还是在物理结构&#xff0c;也就是数据库服务器中存储的…

云原生之使用Docker部署开源建站工具Halo-V2.10版本

云原生之使用Docker部署开源建站工具Halo-V2.10版本 一、Halo-V2.10介绍1.1 Halo简介1.2 Halo特点 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Halo镜像五、部署Halo5.1…

以数据为中心 的AI v.s. 以模型为中心的AI

原文&#xff1a;Data-Centric AI vs. Model-Centric AI Introduction to Data-Centric AI 当你学习关于机器学习相关的课程时&#xff0c;通常是给你一个清洁好的数据,你的任务是利用这个数据集训练出一个最好的模型。所有在机器学习课程教的技巧都是为了这个目标&#xff1…

RT-Thread SMP介绍与移植(学习)

RT-Thread SMP介绍与移植 SMP&#xff1a;对称多处理&#xff08;Symmetrical Multi-Processing&#xff09;简称SMP&#xff0c;是指在一个计算机上汇集了一组处理器&#xff08;多CPU&#xff09;&#xff0c;各CPU之间共享内存子系统以及总线结构。 RT-Thread自4.0.0版本开…

Burstormer论文阅读笔记

这是CVPR2023的一篇连拍图像修复和增强的论文&#xff0c;一作是阿联酋的默罕默德 本 扎耶得人工智能大学&#xff0c;二作是旷视科技。这些作者和CVPR2022的一篇BIPNet&#xff0c;同样是做连拍图像修复和增强的&#xff0c;是同一批。也就是说同一个方向&#xff0c;22年中了…

基于SpringBoot的精准扶贫管理系统

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 贫困户信息管理 新闻类型管理 志愿者招聘管理 志愿者招聘 留言反馈管理 贫困户 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息…

【笔记】【信息论与编码】第三章 离散信源

本文是笔者在学习《信息论与编码》课程中所做的笔记&#xff0c;供个人学习记忆使用。 第三章 离散信源 文章目录 一、离散信源概念离散无记忆信源K重符号序列离散信源 二、离散信源的熵单符号离散无记忆信源熵K重符号序列离散无记忆信源熵K重符号序列离散有记忆信源熵马尔可夫…

如何在Docker部署Drupal并结合内网穿透实现远程访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

NZ系列工具NZ05:VBA不打开工作簿获取其内容

我的教程一共九套及VBA汉英手册一部&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到数据库&#xff0c;到字典&#xff0c;到高级的网抓及类的应用。大家在学习的过程中可能会存在困惑&#xff0c;这么多知识点该如何组织…

Linux 测试端口是否放行

Linux 测试端口是否放行 1、准备2、在 CentOS 7 上放行端口&#xff0c;你可以使用以下方法&#xff1a;4、错误解决&#xff1a;[rootlocalhost backup]# netcat -l -p 11111 netcat: cannot use -p and -l 装了netcat不能用5、能用telnet去测试吗6、效果&#xff1a; 1、准备…

简易计算器的实现:使用C语言进行基础算术运算

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

S/4 HANA 大白话 - 财务会计-4 应付、应收账款

Business Partner 业务伙伴 业务伙伴现在包括供应商伙伴和客户伙伴。 只要不是个搞空壳玩泡沫的公司&#xff0c;你基本都得有从供应商那里拿原材料或者购买零部件&#xff0c;然后进行生产&#xff0c;再售卖给客户。你得和银行打交道&#xff0c;同时也得有员工。所有这些关…

【python自动化神器pyautogui使用步骤】

python自动化神器pyautogui使用步骤 这篇文章主要给大家介绍了关于python自动化神器pyautogui使用步骤的相关资料,在Python当中不仅代码简单,而且有着非常丰富的模块,pyautogui就可以称之为自动化操作的"神器",需要的朋友可以参考下 文章目录 python自动化神器pyauto…

关于SpringBoot2.x集成SpringSecurity+JJWT(0.7.0-->0.11.5)生成Token登录鉴权的问题

项目场景&#xff1a; 问题&#xff1a;遵循版本稳定的前提下&#xff0c;搭建权限认证框架&#xff0c;基于SpringBoot2.xSpringSecurity向上依赖jjwt0.7.0构建用户认证鉴权&#xff0c;起因是某L觉得jjwt0.7.0版本&#xff0c;官方已经放弃维护&#xff0c;且从maven仓库对0…

C++11发展史

文章目录 1.ChatGpt怎么说?2.C官方文档3.C11的诞生4.C11的意义 1.ChatGpt怎么说? C11是C编程语言的一个重要版本&#xff0c;也被称为C0x。它于2011年发布&#xff0c;并引入了许多新的特性和改进&#xff0c;使得C编程更加现代化和强大。 下面是C11的一些主要特性和发展历…