PS:这篇是之前本来就想发的但是一直没时间写,加上今天做了京东的题,结果代码名就命名为jingdong了……懒得改代码名重新跑一遍结果了=。=

暴力法去做就是遍历每个点,判断它是不是“最大点”。判断过程则是又遍历一遍,看看是否存在其他点在它右上方,若存在则不是最大点。O(N^2)

但是这样就会有很多不必要的计算,举个例子(这里暂且当坐标都是int),若存在一个最大点(x0,y0),那么所有在它左下角的点都不用考虑了。

另外,对于(x0,y0),只需要查找在它右边(x>x0)的点是否在它上面。如果预先将点根据x坐标排序,那么判断过程就从for i in [0, n)变成了for i in [x0, n),但这并没有本质的提升,还是O(N^2)。——这也暗示了点集中最右边的点必然是最大点。

然后再注意,如果右边的点存在一个点满足y>y0,那么判断就会返回false了;若不存在则判断返回true。

关键就是记录右边的点的ymax,不必每次都遍历一遍重复计算ymax。

到了这一步后就可以写代码了,注意,由于输入并不是有序的,必须得经过预处理(按照x排序),坐标轴范围是0~1e9的话,用位图法排序(参考编程珠玑)时间复杂度还是1e9的数量级,原题数据量不超过100000,位图法排序并不比快排快。

#include <algorithm>
#include <limits.h>
using namespace std; struct Point
{
int x, y;
}; // a[n]为从输入中读取得到的点集数组
void solution(Point* a, int n)
{
std::sort(a, a + n, [](Point& p1, Point& p2) { return p1.x < p2.x; });
int ymax = INT_MIN; // 记录从右往左遍历过程中y的最大值
for (int i = n - ; i >= ; i--)
{
if (a[i].y > ymax) // 此时a[i].y大于或等于右边所有点的最大y坐标, a[i]为最大点
{
printf("%d %d\n", a[i].x, a[i].y);
ymax = a[i].y; // 更新最大y坐标
}
}
}

上述代码的成功有个前提,也是题目里的限制:【所有点的横纵坐标都不重复】

这点必须注意!如果没有这个限制,比如y坐标不重复,比如对点集(1,1) (2,3) (3,3) (4,2),按照上面的做法只会得出(3,3)和(4,2)两个最大点,但是(2,3)其实也是最大点。

错误的地方在于判断语句:a[i].y > ymax,如果该点的y坐标与ymax相等,那么该点也是最大点.。

因此判断语句要改成

if (a[i].y >= ymax)

如果连x坐标不重复这个限制都没有的话,那就更复杂,比如序列经过sort排序后为(1,3)(1,4)(2,2),(2,2)和(1,4)被确认为最大点,但是判断(1,3)时,由于当前ymax已经被更新为4了,(1,3)不会被当成最大点。

这样一来,逻辑就变成了【对所有满足x=x0的点,其中y>=ymax的点都是最大点】,关键是要找出满足x=x0的点集区间。

在没有【所有的横纵坐标都不重复】这个限制下的完整代码与简单测试结果如下

#include <iostream>
#include <vector>
#include <algorithm>
#include <limits.h>
using namespace std; struct Point
{
int x, y;
Point(int x_, int y_) : x(x_), y(y_) { }
bool operator<(const Point& rhs) const
{
return x < rhs.x;
}
}; void solution(Point* a, int n)
{
vector<Point> res;
res.reserve(n); // 注释掉排序预处理的代码, 输入排序后的结果进行测试
// 因为快排不是稳定排序, 可能打乱x相同的若干点之间的相对顺序
// sort(a, a + n);
int ymax = INT_MIN; // 记录从右往左遍历过程中y的最大值 Point* low = &a[n - ];
Point* high = &a[n]; while (low >= a)
{
// 寻找x坐标相同的左闭右开区间
while (low > a) // 保证low-1在a[n]中
{
auto it = low - ;
if (it->x == low->x)
low = it;
else
break;
}
// 左闭右开区间[low, high)的点的x坐标相同
// 区间内所有y不小于ymax的点均为最大点
int temp = ymax;
for (auto it = low; it != high; ++it)
{
if (it->y >= ymax)
{
res.emplace_back(*it);
if (it->y > temp) // 同时求出[low, a+n)区间的最大y坐标
temp = it->y;
}
}
ymax = temp;
high = low;
low = high - ;
} // 按照x坐标从小到大输出结果
std::sort(res.begin(), res.end());
for (auto& pt : res)
cout << pt.x << " " << pt.y << endl;
} int main()
{
// 读取输入
int n; // 点数
cin >> n;
vector<Point> v;
v.reserve(n);
for (int i = ; i < n; i++)
{
int x,y;
cin >> x >> y;
v.emplace_back(x, y);
} // 计算并输出结果
solution(&v[], v.size());
return ;
}

测试用例data1是针对特殊情况(x/y坐标有重复的)的用例,data2是题目的示意图的用例

xyz@ubuntu:~/Algorithms/$ g++ jingdong.cpp -std=c++
xyz@ubuntu:~/Algorithms/$ cat data1 xyz@ubuntu:~/Algorithms/$ cat data1 | ./a.out xyz@ubuntu:~/Algorithms/$ cat data2 xyz@ubuntu:~/Algorithms/$ cat data2 | ./a.out

如果是在题目限制下的算法,对data1的结果如下(漏掉了(1,3)这个点)

xyz@ubuntu:~/Algorithms/$ g++ jingdong_old.cpp -std=c++
xyz@ubuntu:~/Algorithms/$ cat data1 | ./a.out

2017头条笔试题:二维点集中找出右上角没有点的点并按x坐标从小到大打印坐标的更多相关文章

  1. 《剑指Offer》面试题-二维数组中的查找

    题目1384:二维数组中的查找 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:7318 解决:1418 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到 ...

  2. C#版 - 小红书后台开发面试题: 二维数组中的查找

    二维数组中的查找 热度指数:24274 时间限制:1秒 空间限制:32768K 本题知识点: 查找 ​ 在线提交网址: http://www.nowcoder.com/practice/abc3fe2 ...

  3. 剑指Offer面试题 二维数组中的查找

    题目链接:https://www.nowcoder.com/questionTerminal/abc3fe2ce8e146608e868a70efebf62e 题目大意: 略 分析: 对萌醒很开拓思维 ...

  4. word search(二维数组中查找单词(匹配字符串))

    Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from l ...

  5. 剑指Offer:面试题3——二维数组中的查找(java实现)

    问题描述:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路:取数组中的元素与 ...

  6. 【面试题003】c数组做为参数退化的问题,二维数组中的查找

    [面试题003]c数组做为参数退化的问题,二维数组中的查找  一,c数组做为参数退化的问题 1.c/c++没有记录数组的大小,因此用指针访问数组中的元素的时候,我们要确保没有超过数组的边界, 通过下面 ...

  7. 【剑指offer】面试题 4. 二维数组中的查找

    面试题 4. 二维数组中的查找 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序. 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该 ...

  8. 剑指offer——面试题4:二维数组中的查找

    // 面试题4:二维数组中的查找 // 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按 // 照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个 // 整数 ...

  9. 【剑指Offer面试题】九度OJ1384:二维数组中的查找

    下决心AC全部剑指offer面试题. 九度OJ面试题地址:http://ac.jobdu.com/hhtproblems.php 书籍:何海涛--<剑指Offer:名企面试官精讲典型编程题> ...

随机推荐

  1. PHP:第一章——PHP中的关键字

    <?php //PHP关键词 /* and //php中的逻辑与运算符.(和) or //php中的逻辑或运算符.(或) xor //php中的逻辑异或.(异或) __FILE__ //php中 ...

  2. 【转载】oracle之rowid详解

    原文URL:http://www.2cto.com/database/201109/104961.html 本文讨论的是关于oracle从8i开始引进object的概念后的rowid,即扩展(exte ...

  3. 【转】EDNS

    转自:https://www.cnblogs.com/cobbliu/p/3188632.html 随着业务的复杂化和多样化,RFC1035中定义的DNS消息格式和它支持的消息内容已经不足以满足一些D ...

  4. maven多环境配置

    我们在开发项目的时候,往往会有好几个环境.比如开发.预发布(测试).产品,每个环境一般用到配置都不一样,最典型的就是数据库,开发的数据库与产品的数据库肯定是不一样的,如果要多个环境的切换就得改配置,这 ...

  5. Engineering Management

    Engineering Management 工程師面對工作或挑戰時,可應用以下法則一步一步把工作規管和實施. 1.      Planning 計劃 2.      Organization 組織 ...

  6. jsx介绍

    jsx与传统的html的区别: 1. jsx:使用的“元素”不局限与html中的元素,可以是任何一个React组件,传统的html是做不到的 (区分是否是组件的原则:看第一个字母是否是大写) 2.js ...

  7. 强化学习 reinforcement learning: An Introduction 第一章, tic-and-toc 代码示例 (结构重建版,注释版)

    强化学习入门最经典的数据估计就是那个大名鼎鼎的  reinforcement learning: An Introduction 了,  最近在看这本书,第一章中给出了一个例子用来说明什么是强化学习, ...

  8. OK335xS pwm device register hacking

    /************************************************************************* * OK335xS pwm device regi ...

  9. Nuxt开发搭建博客系统

    nuxt.js第三方插件的使用?路由的配置pages目录自动生成路由layoutsdefault.vueerror.vueVuex的使用权限篇Mysqladvice nuxt.js 追求完美,相信大家 ...

  10. Android Studio - 安卓开发工具 打开后报错集合、修复指南

    安卓开发工具错误修复 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新 ...