大家好,我是吴师兄。
上个月刚过完 32 岁生日,就有人给我转发一个帖子:吴师兄,你这个年纪可不好找工作呀。
说实话,一开始我看到这个帖子的时候,还没太在意,觉得可能就是个网友随便发发的段子,没什么值得深究的。谁知道,打开评论区一看,瞬间炸开了锅,大家纷纷匿名爆料自己所在的公司是如何卡年龄的,有人甚至说,
卡32算什么?直接卡28岁,差不多用完了应届生身份就要丢人
。
这可真是开了眼界。没想到连“32岁”都成了互联网行业的禁忌数字。
之前大家还都在讨论35岁危机,现在却直接提前到了32岁,感觉比“
互联网人永远年轻
”这句话还讽刺。
“35岁危机”,我相信不少人都听过。这是互联网圈的一个潜规则,似乎35岁一到,工作机会就会大大减少,甚至很多企业会默默地把你归为“过时”的一类。你能想到的原因无非就是“年纪大了,不够灵活,体力跟不上,能加班的时间少了,心态也可能更稳定。”这类原因早就不是新闻了,大家心照不宣。
但这次听到32岁就开始“卡”人,我真的有点懵了。
到底是什么原因,让企业把年龄的“红线”提得如此之低?
是技术能力的问题?还是“年轻化”的管理文化在作祟?
你怎么看待这个话题?欢迎在评论区分享你的看法,大家一起聊聊。
回归我们公众号的主题,
每天掌握一道算法题
。
继续来一道和「校招」相关的算法原题。
本原题练习网址:https://www.algomooc.com/problem/P3006
题目描述
同一个数轴
X
上有两个点的集合
A = {A1, A2, …, Am}
和
B = {B1, B2, …, Bn}
,
Ai
和
Bj
均为正整数,
A
、
B
已经按照从小到大排好序。
A
、
B
均不为空,给定一个距离
R
(正整数),列出同时满足如下条件的所有
(Ai, Bj)
数:
-
-
-
在满足条件
1
和
2
的情况下,每个
Ai
只需输出距离最近的
Bj
-
输入描述
第一行三个正整数
m
,
n
,
R
第二行
m
个正整数,表示集合
A
第三行
n
个正整数,表示集合
B
输入限制:
1 <= R <= 100000`,`1 <= n, m <= 100000`,`1 <= Ai, Bj <= 1000000000
输出描述
每组数对输出一行
Ai
和
Bj
,以空格隔开
示例
输入
4 5 5
1 5 5 10
1 3 8 8 20
输出
1 1
5 8
5 8
解题思路
单个Ai的考虑
首先我们考虑单个
Ai
的情况。
要找到
Ai
中距离最近的
Bj
,换句话说就是在数组
B
中找到下一个恰好大于等于
Ai
的数,且距离小于等于
R
。
要找到在
B
数组中下一个恰好大于等于
Ai
的数,这个过程非常简单。
由于
B
数组已经进行了从小到大的排序,这个过程可以用如下的代码来完成
# 遍历B中的每一个元素
for j in range(len(B)):
# 如果B[j]大于等于A[i]
if B[j] >= A[i]:
# 进一步考虑B[j]和A[i]之间的距离是否小于等于R
# 若是,则B[j]是符合要求的元素
if B[j] - A[i] <= R:
print(A[i], B[j])
# 只需要找到一个恰好大于等于A[i]的B[j]即可
break
如果写成
while
循环,则为
j = 0
# 遍历B中的每一个元素
# 退出循环时,若j未越界,则必然存在B[j] >= A[i]
while j and B[j] j += 1
# 退出循环后
# 进一步考虑B[j]和A[i]之间的距离是否小于等于R
# 若是,则B[j]是符合要求的元素
if j and B[j] - A[i] <= R:
print(A[i], B[j])
多个Ai的考虑
单个
Ai
的情况非常简单,我们可以通过一次遍历数组
B
来找到对应的
Bj
。
由于
A
数组也是已经排好序的,我们容易得到以下结论。
在
A
数组中,假设存在两个元素
A1
和
A2
,其中
A1
的位置在
A2
前面(也就是有
A1 <= A2
),它们对应的
B
中的元素分别是
B1
和
B2
,那么
B1
的位置一定不会位于
B2
后面(也就是有
B1 <= B2
)。
更进一步的结论是,假设我们已知
A1
在
B
数组中对应的数组是
B1
,而
A2
是
A1
在
A
中的的下一个元素,那么我们要找到
A2
中对应的
B2
,不用在
B
数组中从头找起,而是直接从
B1
继续往后寻找即可。
那么,我们就可以用两个指针
i
和
j
,来分别作为
A
和
B
数组的索引。
在对某个
A[i]
找到对应的
B[j]
之后,由于
A[i+1]
在
B
中对应的元素索引必然大于等于
j
,因此我们率先令
i
往前移动一步即存在
i += 1
,再在数组
B
中继续向前移动
j
,直到找到第一个大于等于当前
A[i]
的值。
对应的代码为
# 初始化同向双指针i和j均为0
i = 0
j = 0
# 进行i的循环
while i # 遍历B中的每一个元素
# 退出循环时,若j未越界,则必然存在B[j] >= A[i]
while j and B[j] # 在关于j的循环中,j不断前进
j += 1
# 退出循环后
# 进一步考虑B[j]和A[i]之间的距离是否小于等于R
# 若是,则B[j]是符合要求的元素
if j and B[j] - A[i] <= R:
print(A[i], B[j])
# 在关于i的循环中,i不断前进
i += 1
这样我们就用双指针完成了这道题目。
代码
Python
# 题目:https://www.algomooc.com/problem/P3006
# 输入数组A的长度n,数组B的长度m,差值阈值R
n, m, R = map(int, input().split())
# 分别输入数组A和B
A = list(map(int, input().split()))
B = list(map(int, input().split()))
# 初始化同向双指针i和j均为0
i = 0
j = 0
# 进行i的循环
while i # 遍历B中的每一个元素
# 退出循环时,若j未越界,则必然存在B[j] >= A[i]
while j and B[j] # 在关于j的循环中,j不断前进
j += 1
# 退出循环后
# 进一步考虑B[j]和A[i]之间的距离是否小于等于R
# 若是,则B[j]是符合要求的元素
if j and B[j] - A[i] <= R:
print(A[i], B[j])
# 在关于i的循环中,i不断前进
i += 1
Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 输入n, m, R
int n = sc.nextInt();
int m = sc.nextInt();
int R = sc.nextInt();
// 输入数组A和B
int[] A = new int[n];
int[] B = new int[m];
for (int i = 0; i A[i] = sc.nextInt();
}
for (int i = 0; i B[i] = sc.nextInt();
}
// 初始化相向双指针i和j均为0
int i = 0, j = 0;
// 进行i的循环
while (i // 遍历B中的每一个元素
while
(j // 在关于j的循环中,j不断前进
j++;
}
// 退出循环后,进一步考虑B[j]和A[i]之间的距离是否小于等于R
// 若是,则B[j]是符合要求的元素
if (j System.out.println(A[i] + " " + B[j]);
}
// 在关于i的循环中,i不断前进
i++;
}
sc.close();
}
}
C++
#include
#include
using namespace std;
int main() {
int n, m, R;
// 输入n, m, R
cin >> n >> m >> R;
vector<int> A(n), B(m);
// 输入数组A和B
for (int i = 0; i cin >> A[i];
}
for (int i = 0; i cin >> B[i];
}
// 初始化相向双指针i和j均为0
int i = 0, j = 0;
// 进行i的循环
while (i // 遍历B中的每一个元素
while (j // 在关于j的循环中,j不断前进
++j;
}
// 退出循环后,进一步考虑B[j]和A[i]之间的距离是否小于等于R
// 若是,则B[j]是符合要求的元素
if (j cout <" " }
// 在关于i的循环中,i不断前进
++i;
}
return 0;
}
C
#include
int main() {
int n, m, R;
// 输入n, m, R
scanf("%d %d %d", &n, &m, &R);
int A[n], B[m];
// 输入数组A和B
for (int i = 0; i scanf("%d", &A[i]);
}
for (int i = 0; i scanf("%d", &B[i]);
}
// 初始化相向双指针i和j均为0
int i = 0, j = 0;
// 进行i的循环
while (i // 遍历B中的每一个元素
// 退出循环时,若j未越界,则必然存在B[j] >= A[i]
while (j // 在关于j的循环中,j不断前进
j++;
}
// 退出循环后,进一步考虑B[j]和A[i]之间的距离是否小于等于R
// 若是,则B[j]是符合要求的元素
if (j printf("%d %d\n", A[i], B[j]);
}
// 在关于i的循环中,i不断前进
i++;
}
return 0;
}
Node JavaScript
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('', (input) => {
// 输入 n, m, R
let [n, m, R] = input.split(' ').map(Number);
rl.question('', (input) => {
// 输入数组A
let A = input.split(' ').map(Number);
rl.question('', (input) => {
// 输入数组B
let B = input.split(' ').map(Number);
// 初始化相向双指针i和j均为0
let i = 0, j = 0;
// 进行i的循环
while (i // 遍历B中的每一个元素
while (j // 在关于j的循环中,j不断前进
j++;
}
// 退出循环后,进一步考虑B[j]和A[i]之间的距离是否小于等于R
if (j console.log(A[i], B[j]);
}
// 在关于i的循环中,i不断前进
i++;
}
rl.close();
});
});
});
Go
package main
import (
"fmt"
)
func main() {
var n, m, R int
// 输入n, m, R
fmt.Scanf("%d %d %d", &n, &m, &R)
A := make([]int, n)
B := make([]int, m)
// 输入数组A和B
for i := 0; i fmt.Scan(&A[i])
}
for i := 0; i fmt.Scan(&B[i])
}
// 初始化相向双指针i和j均为0
i, j := 0, 0
// 进行i的循环
for i // 遍历B中的每一个元素
for j // 在关于j的循环中,j不断前进
j++
}
// 退出循环后,进一步考虑B[j]和A[i]之间的距离是否小于等于R
if j fmt.Println(A[i], B[j])
}
// 在关于i的循环中,i不断前进
i++
}
}
时空复杂度
时间复杂度:
O(N+M)
。每一个元素至多经过一遍。
空间复杂度:
O(1)
。除了输入的序列,仅需若干常数变量维护遍历过程。
END
一个人盲目刷题会很难,但一群人可以刷得很快。
吴师兄的算法训练营已经陪伴了数千名学员,如果你也想高效刷题,稳稳拿下大厂 offer,
戳链接 🔗
加入我们吧!
这是一个
算法刷题指导 + 高频面试题解析 + 大厂真题讲解 + 模拟机试 + 持续迭代
的算法训练营:
-
300 道 LeetCode 动画题解
,小白也能轻松看懂!
-
-
-
大厂真题 & 面试技巧
,让你少走弯路,直达 offer!
课程更新免费跟进,报名一次,五年有效!同学们的好评已经刷爆了!
如果你觉得内容对你有帮助,不妨随手点个赞、在看、转发三连吧 🌟
最后,送你一句话:跟着吴师兄,算法学习好轻松,吴师兄和算法训练营在你身边~