特斯拉
今年,特斯拉进行过几轮成规模的裁员,其中 4 月份那次 裁员,还对大量应届生进行解约。
但最近几周,仅仅距离特斯拉历史上最大规模的裁员事件过去三个月,特斯拉招聘页面上陆续出现新职位,岗位从「人工智能专家」到「服务岗」等各种类型。
据据彭博社报道,特斯拉正在招聘近 800 名的新员工。
早听说特斯拉的售价时涨时跌,飘忽不定,没想到在企业招聘上也是如此。
特斯拉本次的招聘回暖,或许加大布局「自动驾驶出租车」有关。
自从特斯拉宣布将「自动驾驶出租车原型车」的发布会从 8 月推迟到 10 月,特斯拉的股票开始持续反弹,7 月份以来,特斯拉的涨幅已超过 30%。
北京时间7月16日,特斯拉公司 CEO 埃隆·马斯克(Elon Musk)在 X 发消息回应此前无人驾驶出租车(robotaxi)推迟的传闻。
马斯克表示:公司需要花更多时间推出其自动驾驶出租车,此举旨在对汽车前部进行重要的设计更改,并展示其他一些东西。
宣布大规模裁员后,特斯拉又开始大举招兵买马,大家怎么看?
...
回归主题。
来一道和「特斯拉」相关的题目。
题目描述
平台:LeetCode
题号:398
给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。
您可以假设给定的数字一定存在于数组中。
注意:数组大小可能非常大,使用太多额外空间的解决方案将不会通过测试。
示例:
int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);
// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
solution.pick(3);
// pick(1) 应该返回 0。因为只有nums[0]等于1。
solution.pick(1);
提示:
target
确保存在于nums
中- 最多调用 次的
pick
哈希表+预处理(定长数据流)
为了方便,我们令 nums
的长度为 n
,利用 n
的数据范围为 ,且完整的数组为初始化时已给出,我们可以通过使用「哈希表 + 预处理」的方式进行求解。
具体的,在构造函数传入 nums
时,遍历 nums
并存储每个 对应的下标集合,即使用哈希表以 为键,下标集合 List
作为值进行存储。
在 pick
操作时,通过 的复杂度取出所有 的集合下标,再随机一个下标进行返回。
Java 代码:
class Solution {
Random random = new Random();
Map<Integer, List<Integer>> map = new HashMap<>();
public Solution(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
List<Integer> list = map.getOrDefault(nums[i], new ArrayList<>());
list.add(i);
map.put(nums[i], list);
}
}
public int pick(int target) {
List<Integer> list = map.get(target);
return list.get(random.nextInt(list.size()));
}
}
C++ 代码:
class Solution {
public:
unordered_map<int, vector<int>> map;
Solution(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i++) {
map[nums[i]].push_back(i);
}
}
int pick(int target) {
vector<int>& list = map[target];
return list[rand() % list.size()];
}
};
Python 代码:
class Solution:
def __init__(self, nums: List[int]):
self.mapping = {}
n = len(nums)
for i in range(n):
if nums[i] not in self.mapping:
self.mapping[nums[i]] = []
self.mapping[nums[i]].append(i)
def pick(self, target: int) -> int:
return random.choice(self.mapping.get(target, []))
- 时间复杂度:初始化的复杂度为 ;
pick
操作的复杂度为 - 空间复杂度:
蓄水池抽样(不定长数据流)- TLE
虽然对于本题而言,蓄水池抽样方法(pick
操作复杂度 的)会面临 TLE
。
但当 nums
并不是在初始化时完全给出,而是持续以「流」的形式给出,且数据流的很长,不便进行预处理的话,我们只能使用「蓄水池抽样」的方式求解。
不了解「蓄水池抽样」的同学可以看前置 🧀 : 多语言入门「蓄水池抽样」知识点
具体的,我们在每次 pick
时对流进行遍历,由于数据流很大,我们不能在遍历过程中使用诸如数组的容器存储所有满足条件的下标,只能对于每个 执行「是否要将 i
作为最新答案候选」的操作。
假设共有 m
个下标满足 ,我们需要做到以 1/m
概率返回任一坐标。
我们规定当遇到第 k
个满足 的下标时,执行一次 的随机操作,当随机结果为 0 时(发生概率为 1/k
),我们将该坐标作为最新的答案候选。
当对每一个 的下标都进行上述操作后,容易证明每一位下标返回的概率均为 1/m
。
假设最后返回的是第 k
个满足条件的下标,发生概率为 = 第 k
个下标被候选的概率 后面 k+1
到 m
个下标不被候选的概率 = 。
Java 代码:
class Solution {
Random random = new Random();
int[] nums;
public Solution(int[] _nums) {
nums = _nums;
}
public int pick(int target) {
int n = nums.length, ans = 0;
for (int i = 0, cnt = 0; i < n; i++) {
if (nums[i] == target) {
cnt++;
if (random.nextInt(cnt) == 0) ans = i;
}
}
return ans;
}
}
C++ 代码:
class Solution {
public:
vector<int> nums;
mt19937 random;
Solution(vector<int>& _nums) : nums(_nums) {
srand(time(nullptr));
random.seed(rand());
}
int pick(int target) {
int ans = -1, cnt = 0;
for (size_t i = 0; i < nums.size(); i++) {
if (nums[i] == target) {
cnt++;
if (uniform_int_distribution<>(0, cnt - 1)(random) == 0) {
ans = i;
}
}
}
return ans;
}
};
Python 代码:
class Solution:
def __init__(self, nums: List[int]):
self.nums = nums
def pick(self, target: int) -> int:
ans, cnt = 0, 0
for i in range(len(self.nums)):
if self.nums[i] == target:
cnt += 1
if random.randint(0, cnt - 1) == 0:
ans = i
return ans
- 时间复杂度:初始化的复杂度为 ;
pick
操作的复杂度为 - 空间复杂度: