🎄目录
🌼写在前面
Hello朋友们😋,我是秋刀鱼🐟,一只活跃于Java区与算法区的新人博主~
![]()
欢迎大家加入高校算法学习社区🏰: https://bbs.csdn.net/forums/Suanfa,社区里大佬云集,大家互相交流学习!
今天给大家带来LeetCode 290场单周赛的题目解析,分享一下我解题时的思考过程。如果觉得还不错的话务必三连支持一下博主哦😘
🎉🎉主页:秋刀鱼与猫🎉🎉 🎉🎉期待你的支持与关注~🎉🎉
非常简单的一道题目!
数据的区间范围是: [ 1 , 1000 ] [1,1000] [1,1000],该数据量下可以定义数组记录 [ 1 , 1000 ] [1,1000] [1,1000]每一个数出现的次数。最后按照升序将出现次数为 nums 长度的数输出即可。
class Solution { public List<Integer> intersection(int[][] nums) { int len = nums.length; int[] t = new int[1001]; for (int[] num : nums) { for (int val : num) { t[val]++; } } List<Integer> ans = new ArrayList<>(); for (int i = 0; i <= 1000; ++i) { if (t[i] == len) { ans.add(i); } } return ans; } }
提示:
1 <= circles.length <= 200circles[i].length == 31 <= xi, yi <= 1001 <= ri <= min(xi, yi)
题目中已经给定了圆心 x , y x,y x,y 以及圆半径 r r r 的取值范围,因此可以通过暴力枚举的方式枚举所有可能包含在圆内部区间的点,通过判断枚举点与任意圆心的距离是否小于该圆心对应的半径即可。
class Solution { public int countLatticePoints(int[][] circles) { int res = 0, len = circles.length; for (int i = 0; i <= 200; i++) { for (int j = 0; j <= 200; j++) { for (int k = 0; k < len; k++) { int a = circles[k][0] - i, b = circles[k][1] - j, c = circles[k][2]; if (a * a + b * b <= c * c) { res++; break; } } } } return res; } }
提示:
1 <= rectangles.length, points.length <= 5 * 10e4rectangles[i].length == points[j].length == 21 <= li, xj <= 10e91 <= hi, yj <= 100- 所有
rectangles互不相同 。- 所有
points互不相同 。
核心思路
对于一个点是否能够被矩阵所包含,只需要判断该矩阵右上角坐标: ( x , y ) (x,y) (x,y) 是否都大于等于该点的坐标,如果满足则该点一定能够被矩阵包含。现在将问题转换为求解矩阵右上角坐标 ( x , y ) (x,y) (x,y) 均大于等于该点坐标 ( x i , y i ) (x_i,y_i) (xi,yi) 的矩阵个数。
解题方法
细心的小伙伴可能会发现, y y y 的取值范围为: [ 1 , 100 ] [1,100] [1,100] 。那么假设当前 p o i n t s points points 点的坐标为 ( x i , y i ) (x_i,y_i) (xi,yi) ,于是符合要求的矩阵坐标 ( x , y ) (x,y) (x,y) 一定满足 y ∈ [ y i , 100 ] y\in[y_i,100] y∈[yi,100] 。那么只需要遍历 [ y i , 100 ] [y_i,100] [yi,100] 区间内的所有矩阵坐标,满足 x i < = x x_i<=x xi<=x 的坐标符合题目的要求,将符合要求矩阵的数量输出即是最终答案。
但是上述思路因为数据量太大因此会超时,需要进行算法优化。
如果能够将所有 y y y 相同的矩阵坐标的 x x x 值按照 x x x 递增的次序存储在一个数组中,当遍历 [ y i , 100 ] [y_i,100] [yi,100] 时只需要将对应数组的值按照二分的方式查找第一个大于等于 x i x_i xi 的位置 l l l, n − l n-l n−l的值就是我们需要寻找的值。
此时的时间复杂度为: O ( y ⋅ l g ( x ) ⋅ l e n g t h ) O(y\cdot lg(x) \cdot length) O(y⋅lg(x)⋅length) 符合题目要求,这道题就这样搞定了!
![]()
思路一代码(Java版本)
class Solution {
public int[] countRectangles(int[][] rect, int[][] p) {
int n = p.length;
int[] ans = new int[n];
Arrays.sort(rect, (a, b) -> (a[1] != b[1] ? a[1] - b[1] : a[0] - b[0]));
// pos存放每一个 y 对应的 x 坐标
List<int[]>[] pos = new ArrayList[105];
for (int i = 1; i <= 100; i++) pos[i] = new ArrayList<>();
for (int[] x : rect) pos[x[1]].add(x);
for (int i = 0; i < n; i++) {
int sum = 0;
// 遍历 y 坐标
for (int j = p[i][1]; j <= 100; j++) {
List<int[]> cur = pos[j];
int l = 0, r = cur.size();
// 二分查找实现 upper_bound
while (l < r) {
int mid = l + (r - l) / 2;
if (cur.get(mid)[0] >= p[i][0] && cur.get(mid)[1] >= p[i][1]) r = mid;
else l = mid + 1;
}
sum += cur.size() - l;
}
ans[i] = sum;
}
return ans;
}
}
二维偏序的定义
对于坐标轴中的点 i i i 其坐标为 ( x i , y i ) (x_i,y_i) (xi,yi) ,坐标中其余点的坐标满足 x < = x i x<=x_i x<=xi 且 y < = y i y<=y_i y<=yi 的点数量称为这个点 i i i 的偏序。
例如:下面图中: C C C 点的偏序为 0 , B B B 点的偏序为 2, A A A 点的偏序为 1 图片转自
![]()
求解二维偏序
***本题目中核心思路就是求解偏序,只不过原本偏序的定义需要满足小于等于的条件,而在本题中需要满足大于等于的条件,因此本题对偏序的定义有做修改。***
属于偏序的坐标 ( x , y ) (x,y) (x,y) 一定满足 x > = x i x>=x_i x>=xi 且 y > = y i y>=y_i y>=yi ,其实对于这两个条件我们可以优先满足一个:将二维坐标 ( x , y ) (x,y) (x,y) 按照 x x x 的递增顺序排序,例如下图所示:
那么就拿坐标 ( 3 , 3 ) (3,3) (3,3)来说,其偏序对只有可能出现其后方(因为需要满足 x x x >= x i x_i xi )
很显然橙色方框中的坐标不全都能够组成偏序对,因为偏序对还需要满足第二个条件: y y y >= y i y_i yi ,该条件应该如何判断呢 ?
![]()
这里我使用 树状数组 来解决。对于 ( 3 , 3 ) (3,3) (3,3) 后方的点的 y y y 坐标建立树状数组,树状数组中存储 y y y 出现的次数,定义方法 g e t ( y ) get(y) get(y) 获取 [ 1 , y ] [1,y] [1,y] 坐标数量的总和。
为了判断满足 y > = y i y>=y_i y>=yi 的总数,定义 m a x Y maxY maxY 为 y y y 坐标的最大值,因此只需要在树状数组中查询: g e t ( m a x Y ) − g e t ( y i − 1 ) get(maxY) - get(y_i-1) get(maxY)−get(yi−1) 就是该点 ( x i , y i ) (x_i,y_i) (xi,yi) 的偏序值。
解题思路
有了上面的思路,不难发现其实本题就是求解 p o i n t s points points 数组中每一个点在坐标轴中的偏序值。
按照上面的思路,将所有
rectangles与points的点加入到数组中,加入时需要区分点是从rectangles中加入还是points中加入。
rectangles加入的点需要被更新到树状数组中,points加入的点需要记录其原来在points中的位置,不更新到树状数组。加入完毕后按照 x x x 做降序排序,从第一个点开始遍历,确保树状数组中保存的是 x > = x i x>=x_i x>=xi 坐标的 y y y 信息。
- 如果是
points中的点,需要通过树状数组中的值求出其偏序对并更新到points数组中。- 如果是
rectangles中的点,需要将其 y y y 的值更新到树状数组中。最终遍历完所有点后返回 points 即是最终结果。
思路二代码(Java版本)
class Solution {
class Node {
int x, y, status,from;
Node(int x, int y, int status, int from) {
this.x = x;
this.y = y;
this.status = status;
this.from = from;
}
}
// 记录最大的 y 值
int maxY;
int[] tree;
int lowbit(int val) {
return val & (-val);
}
void update(int idx) {
for (; idx <= maxY; idx += lowbit(idx)) {
tree[idx]++;
}
}
int get(int idx) {
int sum = 0;
for (; idx > 0; idx -= lowbit(idx)) {
sum += tree[idx];
}
return sum;
}
public int[] countRectangles(int[][] rectangles, int[][] points) {
List<Node> nodes = new ArrayList<>();
int[] ret = new int[points.length];
for (int[] rectangle : rectangles) {
nodes.add(new Node(rectangle[0], rectangle[1], -1,-1));
maxY = Math.max(maxY, rectangle[1]);
}
int idx = 0;
for (int[] point : points) {
nodes.add(new Node(point[0], point[1], 1,idx));
maxY = Math.max(maxY, point[1]);
++idx;
}
nodes.sort((a,b)->{
return a.x == b.x ? b.y - a.y : b.x - a.x;
});
tree = new int[maxY + 1];
for (Node node : nodes) {
// 更新树状数组
if (node.status == -1) {
update(node.y);
}
// 求出偏序值
else{
ret[node.from] = get(maxY) - get(node.y - 1);
}
}
return ret;
}
}
提示:
1 <= flowers.length <= 5 * 10e4flowers[i].length == 21 <= starti <= endi <= 10e91 <= persons.length <= 5 * 10e41 <= persons[i] <= 10e9
解题方法
如果将
flowers中每一个区间段称为:[begin,end],那么对于 i i i 时间点,假定其能观赏花的数目为: n u m num num。那么对于 i i i 时间点,如果在 [ 0 , i ] [0,i] [0,i]这段时间中,一共有 n n n 朵花期开始;如果在 [ 0 , i − 1 ] [0,i-1] [0,i−1]这段时间中,一共有 m m m 朵花花期结束,那么此时时间点 i i i 能够欣赏花的数目 n u m = n − m num = n-m num=n−m
因此为了快速获取 n , m n,m n,m 的值,可以将每一个花期的开始时间、结束时间存放在两个 List 中并按照升序排序。对于 i i i 时间点的 n , m n,m n,m 值只需要通过二分查找就可以快速获取,时间复杂度为: O ( n ⋅ l n g ) O(n\cdot lng) O(n⋅lng)
思路一代码(Java版本)
class Solution { public int lower_bound(List<Integer> list, int key) { int l = 0; int r = list.size(); while (l < r) { int m = (l + r) / 2; if (list.get(m) < key) { l = m + 1; }else{ r = m; } } return l; } public int upper_bound(List<Integer> list, int key) { int l = 0; int r = list.size(); while (l < r) { int m = (l + r) / 2; if (list.get(m) <= key) { l = m + 1; }else{ r = m; } } return l; } public int[] fullBloomFlowers(int[][] flowers, int[] persons) { List<Integer> begin = new ArrayList<>(); List<Integer> end = new ArrayList<>(); for (int[] flower : flowers) { begin.add(flower[0]); end.add(flower[1]); } begin.sort((a,b)->{ return a - b;}); end.sort((a, b) -> { return a - b; }); int n = begin.size(); int len = persons.length; for (int i = 0; i < len; ++i) { int cur = persons[i]; int n = upper_bound(begin, cur); int m = lower_bound(end, cur); persons[i] = beginNum - endNum; } return persons; } }
解题方法
将花期分为
begin与end分别表示花期的开始时间与结束时间,将其与persons中查询的时间值x存储并按照递增的顺序排序。同时存储一个标记位来表示该时间值来自于
begin、end、person中的哪一个。我在代码中用INF表示该值为花期的开始时间;-INF表示为花期的结束时间;其余情况表示这是一个请求时间。那么从开始位置进行遍历,使用一个变量
tmp存储当前遍历的时间点花朵的数目。
- 如果遍历到的值为花期开始时间,即:
p.second == INF,则让tmp加一表示进入一个新的花期。- 如果遍历到的值为花期结束时间,即:
p.second == -INF,则让tmp减一表示离开一个新的花期。- 否则表示该遍历的时间点为
persons中查询的时间点,将当前的tmp存储。最终返回结果。
思路一代码(C++版本)
class Solution {
typedef pair<int, int> pii;
const int INF = 1e9+5;
public:
vector<int> fullBloomFlowers(vector<vector<int>>& flowers, vector<int>& persons) {
vector<pii> vec;
for (auto &f : flowers) vec.push_back(pii(f[0], -INF)), vec.push_back(pii(f[1], INF));
for (int i = 0; i < persons.size(); i++) vec.push_back(pii(persons[i], i));
sort(vec.begin(), vec.end());
vector<int> ans(persons.size());
int tmp = 0;
for (pii p : vec) {
if (p.second == -INF) tmp++;
else if (p.second == INF) tmp--;
else ans[p.second] = tmp;
}
return ans;
}
};
💗写在最后
总的来说本次周赛的难度一般,并没有太难的题,甚至我觉得最后一题是我做过最简单的一道困难题😂。不过虽然题目简单但还是需要高度地集中注意力,稍有差错就可能因为忽略题目给定的条件而 WA😇。
最后感谢你能够耐心看完💗
![]()
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).
ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
-if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc
我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr