专栏名称: 吴师兄学算法
和程序员小吴一起从初学者的角度学习算法,以动画的形式呈现解题的思路。每周四篇原创文章,期待你的鉴赏!
目录
相关文章推荐
51好读  ›  专栏  ›  吴师兄学算法

听说互联网不卡35岁了?

吴师兄学算法  · 公众号  ·  · 2025-01-06 16:00

正文

请到「今天看啥」查看全文


大家好,我是吴师兄。

上个月刚过完 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. Ai <= Bj
  2. Ai , Bj 之间的距离小于等于 R
  3. 在满足条件 1 2 的情况下,每个 Ai 只需输出距离最近的 Bj
  4. 输出结果按 Ai 从小到大的顺序排序

输入描述

第一行三个正整数 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<intA(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 := 00

        // 进行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!

课程更新免费跟进,报名一次,五年有效!同学们的好评已经刷爆了!

如果你觉得内容对你有帮助,不妨随手点个赞、在看、转发三连吧 🌟

最后,送你一句话:跟着吴师兄,算法学习好轻松,吴师兄和算法训练营在你身边~







请到「今天看啥」查看全文