1.技术面试题
(1)解释Linux中的进程、线程和守护进程的概念,以及如何管理它们?
答:进程是Linux系统中正在执行的程序的实例,拥有独立的地址空间、系统资源和执行状态。每个进程由唯一的进程ID(PID)标识,通过fork()系统调用创建,父进程与子进程相互独立。进程间通信(IPC)可通过管道、信号、共享内存等方式实现。
管理方法:
查看进程:ps aux 或 top
终止进程:kill 或 pkill <进程名>
后台运行:command &
切换前台/后台:fg %<作业号> 或 bg %<作业号>
线程是进程内的执行单元,共享同一进程的地址空间和资源,但拥有独立的栈和寄存器。线程轻量级,创建和切换开销小,适合高并发任务。Linux通过POSIX线程(pthread)库实现多线程。
管理方法:
查看线程:ps -eLf 或 top -H
线程编程:使用pthread_create()等函数(需链接-lpthread库)
调试工具:gdb 或 strace -f
守护进程是在后台长期运行的特殊进程,通常以d结尾(如httpd)。它脱离终端控制,以系统服务形式存在,通常由init进程(PID=1)管理。常见于日志服务、网络服务等。
管理方法:
创建步骤:调用fork()后退出父进程,调用setsid()创建新会话,关闭文件描述符,切换工作目录。
系统管理:
启动/停止:systemctl start|stop <服务名>
查看状态:systemctl status <服务名>
开机自启:systemctl enable <服务名>
(2)请详细描述OSI七层模型和TCP/IP四层模型,并说明它们之间的对应关系。每一层的主要功能是什么?各层有哪些典型的协议?
答:OSI七层模型
OSI(开放系统互连)模型是一个理论框架,将网络通信分为七层,每层具有独立功能:
物理层:
负责传输原始比特流,定义电气、机械和时序接口标准。
典型协议:Ethernet(物理层部分)、RS-232、USB。
数据链路层:
提供节点到节点的可靠传输,处理帧同步、错误检测(如CRC)和流量控制。
典型协议:Ethernet(MAC层)、PPP、HDLC、VLAN。
网络层:
负责路由选择、分组转发和逻辑寻址(如IP地址)。
典型协议:IP、ICMP、ARP、RIP、OSPF。
传输层:
提供端到端的可靠或不可靠数据传输,处理错误恢复和流量控制。
典型协议:TCP(可靠)、UDP(不可靠)、SCTP。
会话层:
管理会话建立、维护和终止,支持同步点机制。
典型协议:NetBIOS、RPC、SSH(部分功能)。
表示层:
处理数据格式转换、加密/解密和压缩。
典型协议:SSL/TLS(加密)、JPEG(格式)。
应用层:
直接为用户应用提供服务,如文件传输或电子邮件。
典型协议:HTTP、FTP、SMTP、DNS。
TCP/IP四层模型
TCP/IP模型是实际工程中广泛使用的协议栈,分为四层:
网络接口层:
对应OSI的物理层和数据链路层,负责硬件寻址和物理传输。
典型协议:Ethernet、Wi-Fi(IEEE 802.11)、ARP。
网络层:
对应OSI的网络层,核心功能是路由和寻址。
典型协议:IP、ICMP、IGMP。
传输层:
与OSI传输层一致,提供端到端通信。
典型协议:TCP、UDP。
应用层:
合并了OSI的应用层、表示层和会话层功能,直接面向用户。
典型协议:HTTP、FTP、DNS、SMTP、Telnet。
(3)详细介绍什么是最大堆/最小堆。
答:最大堆和最小堆是完全二叉树的数据结构,满足特定堆性质:
最大堆:每个节点的值大于或等于其子节点的值,根节点为最大值。
最小堆:每个节点的值小于或等于其子节点的值,根节点为最小值。
完全二叉树结构:除最后一层外,其他层节点必须填满,最后一层从左到右填充。
堆序性:
最大堆中,父节点值 ≥ 子节点值。
最小堆中,父节点值 ≤ 子节点值。
数组表示:堆通常用数组存储,索引关系为(假设根索引为0):
父节点索引:(i-1)//2
左子节点索引:2i+1
右子节点索引:2i+2
操作:
插入元素(上浮)
将新元素添加到堆的末尾。
比较新元素与其父节点,若违反堆性质则交换,递归直到满足条件。
删除根节点(下沉)
移除根节点,将末尾元素移至根位置。
比较新根与子节点,若违反堆性质则与较大(最大堆)或较小(最小堆)的子节点交换,递归调整。
构建堆
从最后一个非叶子节点开始,依次对每个节点执行下沉操作,时间复杂度为 O(n)。
(4)详细介绍什么是二分搜索树。
答:二分搜索树是一种特殊的二叉树数据结构,满足以下性质:
每个节点的左子树中所有节点的值均小于该节点的值。
每个节点的右子树中所有节点的值均大于该节点的值。
左右子树也分别为二分搜索树。
性质:
有序性:通过中序遍历(左-根-右)可得到有序序列。
高效查找:平均时间复杂度为 O(logn)O(\log n)O(logn),最坏情况下(退化为链表)为 O(n)O(n)O(n)。
动态操作:支持插入、删除、查找等操作,且保持结构性质。
操作:
插入操作:
若树为空,直接创建新节点作为根节点。
比较待插入值与当前节点值,递归进入左子树(值更小)或右子树(值更大)直至找到空位。
删除操作:
叶子节点:直接删除。
单子节点:用子节点替代被删节点。
双子节点:用右子树的最小节点(或左子树的最大节点)替代被删节点,并递归删除该替代节点。
查找操作:
从根节点开始,若目标值等于当前节点值则返回;若更小则搜索左子树,否则搜索右子树。
2.HR面试题
(1)我们非常欣赏你的能力,但目前只能提供比你期望薪资低20%的offer。在这种情况下,你会接受这份工作吗?如果接受,你对未来薪资增长有什么期望?如果不接受,你的底线是什么?
答:首先感谢公司对我的认可,基于对公司和岗位的强烈兴趣,我愿意在薪资上适当妥协。但希望能在入职后3个月内重新评估薪资,当我的贡献得到验证时,调整至市场水平(或原期望值)。您认为这样的安排是否可行?
(2)我们公司经常需要加班到深夜,有时甚至需要周末工作。你如何看待这种工作强度?你认为工作与生活的理想平衡点在哪里?
答:关于工作与生活的平衡,我的观点是:短期的冲刺可以接受,但长期来看,适当的休息和充电能让人保持更好的创作力和稳定性。比如,我会利用周末的碎片时间学习行业新知识,这对工作也是一种间接支持。
(3)你认为自己最大的优势是什么?这个优势如何帮助你胜任我们这个岗位?
答:我认为自己最大的优势是将复杂问题模块化的能力。
(4)你认为这份工作能为你带来什么?你能为公司创造什么价值?
答:首先这份工作能让我在行业平台获得成长,积累重要项目经验;再一个就是必不可少的薪资,作为回报,我能为公司带来技术创新和效率提升,比如运用我所学技术优化现有流程可节省10%的时间。我相信通过我的技术能力和行业经验,能为团队目标实现做出重要贡献。
3.问答题
(1)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
result = []
for i in range(len(lst)):
if i == len(lst) - 1:
result.append(lst[i] * 2)
elif lst[i] < lst[i+1]:
result.append(lst[i] + 1)
else:
result.append(lst[i] - 1)
return result
print(func([5, 3, 7, 2]))
答:输出结果为 [4, 4, 6, 4]。
函数 func 对输入的列表 lst 进行遍历,并根据特定规则修改每个元素的值。
具体执行过程(以输入 [5, 3, 7, 2] 为例):
处理规则:
当元素是列表的最后一个时(i == len(lst) - 1),将该元素乘以 2。
当当前元素小于下一个元素(lst[i] < lst[i+1]),将当前元素加 1。
当当前元素大于或等于下一个元素(else 分支),将当前元素减 1。
处理过程:
处理 5(索引 0):
下一个元素是 3,5 < 3 为假,执行 else 分支:5 - 1 = 4。
处理 3(索引 1):
下一个元素是 7,3 < 7 为真,执行 3 + 1 = 4。
处理 7(索引 2):
下一个元素是 2,7 < 2 为假,执行 7 - 1 = 6。
处理 2(索引 3):
是最后一个元素,执行 2 * 2 = 4。
最终生成的结果列表为 [4, 4, 6, 4]。
(2)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
result = []
for num in lst:
if num % 3 == 0:
result.append(num // 3)
elif num % 2 == 0:
result.append(num * 2)
if num > 10:
break
else:
result.append(num + 1)
return result
print(func([9, 4, 12, 7, 14]))
答:输出结果为:[3, 8, 4, 8]。
函数 func 对输入的列表 lst 中的每个元素进行条件判断和处理。
处理规则:
能被3整除的元素:将元素除以3并取整(num // 3),结果加入 result 列表。
示例:9 满足条件,处理后为 9 // 3 = 3。
能被2整除的元素:将元素乘以2(num * 2),结果加入 result 列表。若该元素大于10,则终止整个循环。
示例:4 满足条件,处理后为 4 * 2 = 8;14 满足 num > 10,触发 break,后续元素 7 未被处理。
其他情况:将元素加1(num + 1),结果加入 result 列表。
示例:7 不满足前两个条件,处理后为 7 + 1 = 8。
处理过程:
输入列表 [9, 4, 12, 7, 14] :
9:满足 num % 3 == 0 → 9 // 3 = 3 → result = [3]
4:满足 num % 2 == 0 → 4 * 2 = 8 → result = [3, 8]
12:满足 num % 3 == 0 → 12 // 3 = 4 → result = [3, 8, 4]
7:不满足前两个条件 → 7 + 1 = 8 → result = [3, 8, 4, 8]
14:满足 num % 2 == 0 且 num > 10 → 触发 break,循环终止。
最终返回的 result 为 [3, 8, 4, 8]。
(3)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(nums1, m, nums2, n):
i = j = k = 0
temp = nums1.copy()
while i < m and j < n:
if temp[i] < nums2[j]:
nums1[k] = temp[i]
i += 1
else:
nums1[k] = nums2[j]
j += 1
k += 1
while i < m:
nums1[k] = temp[i]
i += 1
k += 1
return nums1
nums1 = [1, 3, 5, 0, 0]
m = 3
nums2 = [2, 4]
n = 2
print(func(nums1, m, nums2, n))
答:输出结果为:[1, 2, 3, 4, 5]。
函数 func 实现了两个已排序数组合并的功能,将 nums2 合并到 nums1 中,并保持合并后的数组有序。具体逻辑如下:
函数接收四个参数:nums1(目标数组,预留了足够空间)、m(nums1 中有效元素数量)、nums2(待合并数组)、n(nums2 的有效元素数量)。
通过 temp 复制 nums1 的原始数据,避免直接修改导致数据覆盖问题。
使用双指针 i 和 j 分别遍历 temp 和 nums2,比较当前元素大小,将较小的值依次填充到 nums1 中。
若某一数组遍历完成后,将剩余元素直接追加到 nums1 的末尾。
处理规则:
初始化指针和临时数组
i、j、k 初始化为 0,temp 保存 nums1 的原始数据。
双指针比较与合并
通过循环比较 temp[i] 和 nums2[j],将较小值存入 nums1[k],并移动对应指针。
处理剩余元素
若 temp 或 nums2 有剩余未遍历元素,直接按序填入 nums1。
处理过程:
输入:
nums1 = [1, 3, 5, 0, 0](有效部分 [1, 3, 5]),
nums2 = [2, 4]。
合并过程:
依次比较并填充 1、2、3、4,最后将剩余的 5 填入,得到有序结果 [1, 2, 3, 4, 5]。
(4)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
total = 0
for i in range(len(lst)):
if i % 2 == 0:
total += lst[i]
else:
total -= lst[i]
if total < 0:
total = 0
return total
print(func([5, 3, 2, 7, 1]))
答:输出结果为 1。
函数 func 的功能可以分解为以下几点:
遍历列表并交替加减元素:
函数接收一个列表 lst,初始化 total 为 0。遍历列表时,对索引为偶数的元素(第0、2、4…项)执行加法操作,对索引为奇数的元素(第1、3、5…项)执行减法操作。
非负约束:
每次更新 total 后,检查其值是否小于 0。若为负,则重置 total 为 0,确保累加结果始终为非负数。
返回最终累加值:
遍历结束后,返回最终的 total 值。
处理过程:
以输入 [5, 3, 2, 7, 1] 为例:
索引 0(值 5):total = 0 + 5 = 5
索引 1(值 3):total = 5 - 3 = 2
索引 2(值 2):total = 2 + 2 = 4
索引 3(值 7):total = 4 - 7 = -3 → 重置为 0
索引 4(值 1):total = 0 + 1 = 1
最终返回 total = 1。
(5)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
evens = []
odds = []
for num in lst:
if num % 2 == 0:
evens.append(num)
else:
odds.append(num)
evens.sort()
odds.sort(reverse=True)
return evens + odds
print(func([3, 1, 4, 1, 5, 9, 2, 6, 5]))
答:输出结果为:[2, 4, 6, 9, 5, 5, 3, 1, 1]。
函数 func 的主要功能是对输入的列表 lst 进行以下处理:
分类奇偶数:
遍历列表中的每个元素,将偶数存入 evens 列表,奇数存入 odds 列表。
排序处理:
偶数列表 evens 按升序排列(默认 sort() 行为)。
奇数列表 odds 按降序排列(通过 sort(reverse=True) 实现)。
合并结果:
将排序后的偶数列表和奇数列表合并(evens 在前,odds 在后),并返回最终的组合列表。
处理过程:
以输入 [3, 1, 4, 1, 5, 9, 2, 6, 5] 为例:
偶数部分:[4, 2, 6] → 升序后为 [2, 4, 6]。
奇数部分:[3, 1, 1, 5, 9, 5] → 降序后为 [9, 5, 5, 3, 1, 1]。
合并结果:[2, 4, 6] + [9, 5, 5, 3, 1, 1] = [2, 4, 6, 9, 5, 5, 3, 1, 1]。
(6)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
result = []
for i in range(len(lst)):
current = lst.pop(0)
if current % 2 == 0:
lst.append(current * 2)
else:
result.append(current)
return result + lst
data = [1, 2, 3, 4, 5]
print(func(data))
答:输出结果为:[1, 3, 5, 4, 8]。
函数 func 对输入的列表 lst 进行以下操作:
遍历列表:通过 for 循环遍历列表的原始长度(len(lst) 在开始时确定)。
处理偶数元素:每次从列表头部弹出元素(lst.pop(0)),若该元素为偶数,则将其乘以 2 后追加到列表末尾。
收集奇数元素:若弹出的元素为奇数,则直接将其加入结果列表 result。
合并结果:最终将剩余的列表 lst(经过偶数处理后)拼接到 result 后返回。
处理过程:
以输入 data = [1, 2, 3, 4, 5] 为例:
初始 lst = [1, 2, 3, 4, 5],result = []。
弹出 1(奇数),result = [1],lst = [2, 3, 4, 5]。
弹出 2(偶数),lst = [3, 4, 5, 4](22=4 追加到末尾)。
弹出 3(奇数),result = [1, 3],lst = [4, 5, 4]。
弹出 4(偶数),lst = [5, 4, 8](42=8 追加到末尾)。
弹出 5(奇数),result = [1, 3, 5],lst = [4, 8]。
循环结束,返回 result + lst = [1, 3, 5, 4, 8]。
(7)以下代码运行结果是?并阐述函数func的主要功能是什么?
def func(lst):
result = []
for i in range(len(lst)):
for j in range(i+1, len(lst)):
if lst[i] + lst[j] == 10:
result.append((lst[i], lst[j]))
break
return result
print(func([5, 3, 7, 2, 8]))
答:输出结果为:[(3, 7), (2, 8)]。
函数 func 的功能是遍历输入列表 lst,找出所有满足以下条件的整数对 (lst[i], lst[j]):
两数之和等于 10(即 lst[i] + lst[j] == 10)。
每个元素 lst[i] 只会与后续元素 lst[j](j > i)配对一次,找到第一个满足条件的 j 后即终止内层循环(通过 break 实现)。
处理过程:
以输入 [5, 3, 7, 2, 8] 为例:
外层循环 i=0(元素 5),内层循环找到 j=1(元素 3),不满足 5 + 3 == 10,终止内层循环。
外层循环 i=1(元素 3),内层循环找到 j=2(元素 7),满足 3 + 7 == 10,记录 (3, 7) 并终止内层循环。
外层循环 i=3(元素 2),内层循环找到 j=4(元素 8),满足 2 + 8 == 10,记录 (2, 8) 并终止内层循环。
(8)编写程序,反素数
反素数是指一个将其逆向拼写后也是一个素数的非回文数,例如17和71都是素数但不是回文数,且反转后依旧是素数
输出显示前100个反素数,每行显示10个
答:
# Your Codes
def is_prime_A(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
count = 0
num = 10
while count < 100:
rev = int(str(num)[::-1])
if num != rev and is_prime_A(num) and is_prime_A(rev):
print(num, end=" ")
count += 1
if count % 10 == 0:
print()
num += 1
(9)编写程序,梅森素数
如果一个素数可以写成2p−12^p-12p−1的形式,其中p是某个正整数,那么这个素数就称作梅森素数
输出p≤31的所有梅森素数
答:
# Your Codes
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
for p in range(1, 32):
m = 2 ** p - 1
if is_prime(m):
print(f"p={p}: {m}")
(10)编写程序,数列求和
编写一个函数计算下面的数列:
m(i)=12+23+...+ii+1m(i) = \frac{1}{2} + \frac{2}{3} + ... + \frac{i}{i + 1}m(i)=21+32+...+i+1i
并输出测试结果:
i m(i)
1 0.500
2 1.16
...
19 16.40
20 17/35
答:
# Your Codes
def m(i):
total = 0
for k in range(1, i+1):
total += k / (k + 1)
return total
print("i\tm(i)")
for i in range(1, 21):
print(f"{i}\t{m(i):.3f}")
(11)编写程序,组合问题
有1、2、3、4这个四个数字,能组成多少个互不相同且无重复数字的三位数?分别又是多少?
答:
# Your Codes
from itertools import permutations
nums = [1, 2, 3, 4]
count = 0
for p in permutations(nums, 3):
print(''.join(map(str, p)), end=' ')
count += 1
print(f"\nTotal: {count}")
(12)编写程序,计算e
你可以使用下面的数列近似计算e
e=1+11!+12!+13!+14!+...+1i!
e=1+\frac{1}{1!}+\frac{1}{2!}+\frac{1}{3!}+\frac{1}{4!}+...+\frac{1}{i!}
e=1+1!1+2!1+3!1+4!1+...+i!1
当i越大时,计算结果越近似于e
答:
# Your Codes
import math
def calc_e(n):
return sum(1/math.factorial(i) for i in range(n+1))
for i in [1,5,10,20,30,40,80,120]:
print(f"i={i}: {calc_e(i)}")
(13)编写程序,完全数
如果一个正整数等于除了它本身之外所有正因子的和,那么这个数称为完全数
例如 6 = 3 + 2 + 1,28 = 14 + 7 + 4 + 2 + 1
输入输出描述
输入一个正整数
输出该数是否为完全数
示例1
输入:
6
输出:
Yes
示例2
输入:
9
输出:
No
答:
# Your Codes
def A(n):
B = [i for i in range(1, n) if n % i == 0]
return sum(B) == n if n > 1 else False
num = int(input())
print("Yes" if A(num) else "No")
83

被折叠的 条评论
为什么被折叠?



