T2.小牛架炮 - 美团机试真题题解

devtools/2025/3/19 3:17:50/

题目描述

在无限大的棋盘中有n个炮,第个炮的坐标是(xi,yi)。

已知每个炮的攻击方式是:先选一个攻击方向(上、下、左、右),该方向上看见的第一个棋子为“炮架”,该炮可以通过炮架攻击到炮架后面的棋子(只能攻击到炮架后面的第一个)。

小牛希望你求出每个炮第一次攻击能攻击到多少个炮。

输入描述

第一行输入一个正整数n,代表炮的数量。
接下来的几行,每行输入两个整数xi,yi,代表每个炮所在的坐标。
1<=n<=10^5
-10^9 <=xi,yi<= 10^9

输出描述

输出几行,每行输出一个整数,代表第i个炮可以攻击到的炮的数量。

示例1

输入:
6 
0 0 
0 1 
0 2 
1 0 
2 0 
3 0输出:
2
0
1
1
1
1

C++

#include <bits/stdc++.h>using namespace std;// 记录同一行的所有炮,key为行号,value为<列号, 炮的序号>
unordered_map<int, vector<pair<int, int>>> rows;
// 记录同一列的所有炮,key为列号,value为<行号, 炮的序号>
unordered_map<int, vector<pair<int, int>>> cols;int main() {int n;cin >> n;// 记录每个炮的攻击目标数vector<int> ans(n);// 读取输入数据for (int i = 0, x, y; i < n; i++) {cin >> x >> y;rows[x].emplace_back(y, i); // 按行分类,存储列号和炮的索引cols[y].emplace_back(x, i); // 按列分类,存储行号和炮的索引}// 遍历所有行,统计每个炮能攻击到的炮for (auto &p: rows) {vector<pair<int, int>> &lst = p.second;sort(lst.begin(), lst.end()); // 按列号排序for (int i = 0; i < lst.size(); i++) {int idx = lst[i].second;// 如果该炮右侧有两个炮,则可以攻击右侧if (i + 2 < lst.size()) ans[idx]++;// 如果该炮左侧有两个炮,则可以攻击左侧if (i - 2 >= 0) ans[idx]++;}}// 遍历所有列,统计每个炮能攻击到的炮for (auto &p: cols) {vector<pair<int, int>> &lst = p.second;sort(lst.begin(), lst.end()); // 按行号排序for (int i = 0; i < lst.size(); i++) {int idx = lst[i].second;// 如果该炮下侧有两个炮,则可以攻击下侧if (i + 2 < lst.size()) ans[idx]++;// 如果该炮上侧有两个炮,则可以攻击上侧if (i - 2 >= 0) ans[idx]++;}}// 输出每个炮能攻击的目标数for (int cnt: ans) {cout << cnt << endl;}return 0;
}

题目类型

本题属于 哈希表 + 排序 结合的题目,同时具有 扫描线思想,因为我们需要分别统计同一行和同一列上的炮的情况,以确定每个炮的攻击目标。


解题思路

1. 题目解析

  • 题目给定 n 个炮的坐标,炮的攻击方式是在选择一个方向(上、下、左、右)后,找到该方向上的 第一个棋子作为炮架,然后攻击炮架后面 最近的炮
  • 需要计算 每个炮可以攻击到的炮的数量

2. 主要思路

为了高效求解,可以采用 哈希表 + 排序 的方法:

  1. 使用哈希表分类存储炮的位置

    • unordered_map<int, vector<pair<int, int>>> rows 存储 同一行 的炮,key 为 行号,value 为 (列号,炮的索引)
    • unordered_map<int, vector<pair<int, int>>> cols 存储 同一列 的炮,key 为 列号,value 为 (行号,炮的索引)
  2. 对每一行、每一列的炮进行排序

    • 按照 列号 对同一行的炮进行排序,遍历后计算每个炮的可攻击数量。
    • 按照 行号 对同一列的炮进行排序,遍历后计算每个炮的可攻击数量。
  3. 计算每个炮的攻击目标

    • 经过排序后,我们遍历 每一行,如果某个炮 左侧第二个 存在,它可以攻击左侧目标;如果 右侧第二个 存在,它可以攻击右侧目标。
    • 同样遍历 每一列,如果某个炮 上侧第二个 存在,它可以攻击上侧目标;如果 下侧第二个 存在,它可以攻击下侧目标。
  4. 输出结果:每个炮能攻击到的炮的总数。

时间复杂度分析

  • 构造哈希表 需要遍历所有炮,时间复杂度为 O(n)

  • 排序部分:

    • 每个行/列最多包含 n 个元素,排序的时间复杂度为 O(k log k),其中 k 是该行/列的炮的数量。
  • 由于最坏情况下 所有炮都在同一行或同一列,排序时间复杂度为 O(n log n)

    • 遍历计算攻击目标 也是 O(n)

    综上,总时间复杂度为 O(n log n),可以高效处理 n ≤ 10^5 的情况。


空间复杂度分析

  • 哈希表 rowscols:在最坏情况下,所有炮分布在同一行或列,存储 O(n) 个元素。
  • 数组 ans:大小为 O(n)
  • 排序的临时空间:排序 O(1) 额外空间。

综上,总空间复杂度为 O(n)

整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。🙏🙏🙏


http://www.ppmy.cn/devtools/168225.html

相关文章

Python 基础知识整理笔记

闹麻了&#xff0c;因为各种原因&#xff0c;现在需要重新回顾一下Python&#xff0c;话不多说&#xff0c;开始吧 1. Python是解释型语言 && Python与C代码执行过程的区别&#xff1a; &#xff08;1&#xff09;C 源码&#xff08;Source&#xff09;&#xff1a;C的…

PHP语言的开源贡献

PHP语言的开源贡献及其影响 引言 在互联网技术飞速发展的今天&#xff0c;开源软件已经成为了软件开发的重要组成部分。它不仅改变了我们开发和使用软件的方式&#xff0c;更在促进技术共享、推动创新和降低开发成本等方面发挥了重要作用。而在众多的开源项目中&#xff0c;P…

组播实验--IGMP、IGMP Snooping 及 PIM-DM 协议

4台路由器之间运行OSPF路由协议&#xff0c;均创建Loopback0&#xff0c;IP地址为10.0.x.x/32。4台路由器之间构成一个组播网络&#xff0c;AR1作为第一跳路由器连接组播源239.0.0.12&#xff0c;AR4作为最后一跳路由器连接组播组239.0.0.12的接收者&#xff0c;为了能够让组播…

鸿蒙 Next 实现线程之间的通信

鸿蒙 Next 实现线程之间的通信 在鸿蒙 Next 开发中&#xff0c;线程间通信是一个常见需求&#xff0c;尤其是在多线程任务处理中。鸿蒙 Next 提供了多种机制来实现线程间通信&#xff0c;包括事件驱动的 Emitter、共享内存 SharedArrayBuffer 以及基于消息传递的 Worker 和 Ta…

通过 CSS 的 命名页面(Named Pages) 技术实现作用域隔离,实现 @page 样式仅影响当前组件

以下是实现 page 样式仅影响当前组件的完整解决方案&#xff0c;通过 CSS 的 命名页面&#xff08;Named Pages&#xff09; 技术实现作用域隔离&#xff1a; vue <template><div><button v-print"printOptions">打印当前报表</button><…

MySQL复习笔记

文章目录 1.MySQL1.1什么是数据库1.2 数据库分类1.3 MySQL简介1.4连接数据库 2. 操作数据库2.1 操作数据库2.2 数据库的列类型2.3 数据库的字段属性&#xff08;重点&#xff09;2.4 创建数据库表&#xff08;重点&#xff09;2.5 数据表的类型2.6 修改数据表 3. MySQL 数据管理…

WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271)深度解析与实战复现

0x00 漏洞概述 CVE-2017-10271 是Oracle WebLogic Server WLS Security组件中的远程代码执行漏洞。攻击者通过构造恶意XML请求&#xff0c;利用XMLDecoder反序列化机制绕过安全验证&#xff0c;最终实现服务器权限接管。 影响版本 WebLogic 10.3.6.0WebLogic 12.1.3.0WebLog…

第十五届蓝桥杯C/C++B组拔河问题详解

解题思路 这道题目的难点在于枚举所有区间&#xff0c;并且区间不能重合&#xff0c;那么这样感觉就很难了。但是用下面这种方法就会好很多。 我们只需要将左边的所有区间的各种和放在一个set中&#xff0c;然后我们在枚举右边的所有区间的和去和它进行比较&#xff0c;然后…