特斯拉产品研发创新中心 3月 22 日笔试答案

简介: 昨天是 ****「特斯拉 2023 春季公开笔试 - 产品研发创新中心专场」****,你参加了吗?这场笔试整体来看没有难到特别离谱的题,但需要一些思维。
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。

大家好,我是小彭。

昨天是 「特斯拉 2023 春季公开笔试 - 产品研发创新中心专场」,你参加了吗?这场笔试整体来看没有难到特别离谱的题,但需要一些思维。


竞赛题解一览

T1 · 亲密字符串(Easy)

  • 题解:模拟 $O(n + C)$

T2 · 数青蛙(Medium)

  • 题解:模拟 $O(n + C)$

T3 · 复原 IP 地址(Medium)

  • 题解:回溯 $O(3^4·n)$

T4 · 课程表 III(Hard)

  • 题解:贪心 + 大顶堆 $O(nlgn + n)$


T1 · 亲密字符串(Easy)

题目地址

https://leetcode.cn/problems/buddy-strings/

题目描述

给你两个字符串 s 和 goal ,只要我们可以通过交换 s 中的两个字母得到与 goal 相等的结果,就返回 true ;否则返回 false 。

交换字母的定义是:取两个下标 i 和 j (下标从 0 开始)且满足 i != j ,接着交换 s[i] 和 s[j] 处的字符。

  • 例如,在 "abcd" 中交换下标 0 和下标 2 的元素可以生成 "cbad" 。

题解(模拟)

简单模拟题。

  • 如果 sgoal 的长度不同或者词频不同,则必然不符;
  • 如果 sgoal 不相符的位置数量超过 2,则必然不符;
  • 如果 sgoal 不相符的位置数量为 2,则必然相符(因为词频相同,所以可以不用判断这两个位置上的字符是否对立);
  • 如果 sgoal 不相符的位置数量为 1,则必然不符;
  • 如果 sgoal 不相符的位置数量为 0,则需要判断是否至少存在一个字符的词频大于 1。
class Solution {
    fun buddyStrings(s: String, goal: String): Boolean {
        // 长度不同
        if (s.length != goal.length) return false
        // 计数
        var diff = 0
        val cnts1 = IntArray(26)
        val cnts2 = IntArray(26)
        for (index in s.indices) {
            cnts1[s[index] - 'a']++
            cnts2[goal[index] - 'a']++
            // 字符不匹配
            if (s[index] != goal[index]) diff++
        }
        // 检查
        var flag = false
        for (index in cnts1.indices) {
            // 词频不同
            if (cnts1[index] != cnts2[index]) return false
            // 词频大于等于 2
            if (cnts1[index] >= 2) flag = true
        }
        return diff == 2 || (diff == 0 && flag)
    }
}

复杂度分析:

  • 时间复杂度:$O(n + C)$ 其中 $n$ 是 $nums$ 数组的长度,$C$ 是字符集大小,$C$ 为常数 $26$;
  • 空间复杂度:$O(C)$ 计数数组空间。

相似题目:


T2 · 数青蛙(Medium)

题目地址

https://leetcode.cn/problems/minimum-number-of-frogs-croaking/

题目描述

给你一个字符串 croakOfFrogs,它表示不同青蛙发出的蛙鸣声(字符串 "croak" )的组合。由于同一时间可以有多只青蛙呱呱作响,所以 croakOfFrogs 中会混合多个 “croak” 

请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。

要想发出蛙鸣 "croak",青蛙必须 依序 输出 ‘c’, ’r’, ’o’, ’a’, ’k’ 这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。如果字符串 croakOfFrogs 不是由若干有效的 "croak" 字符混合而成,请返回 -1 。

题解(模拟)

中等模拟题,这道题卡了很久,浪费很多时间在思考栈、队列、单调队列等方向上。

我们发现:合法的青蛙叫声应该是按照 c → r → o → a → k 的顺序出现的,因此,叫声的每个阶段必然是(非严格)递增的。例如示例 crcaokroak 非法:在处理到第一个 'a' 的位置时,'a' 的计数是 1,'o' 的计数是 0,所以必然不合法。

因此,我们可以维护每个字符的出现次数,在处理每个字符时先累加当前字符的出现次数,再检查上一个阶段的字符的出现次数是否大于等于当前字符的出现次数('c' 不需要检查)。

另外,题目要求的是最多青蛙数量,答案应该记录 'c''k' 字符的最大差值。

class Solution {
    fun minNumberOfFrogs(croakOfFrogs: String): Int {
        // 字符映射到数字
        val ids = mapOf('c' to 0, 'r' to 1, 'o' to 2, 'a' to 3, 'k' to 4)
        var ret = 0
        // 字符计数
        val cnts = IntArray(5)
        // 枚举字符
        for (c in croakOfFrogs) {
            ++cnts[ids[c]!!]
            // 检查上一个阶段的字符是否足够
            if ('c' != c && cnts[ids[c]!! - 1] < cnts[ids[c]!!]) return -1
            // 记录最大差值
            ret = Math.max(ret, cnts[0] - cnts[4])
        }
        // 检查各个阶段出现次数是否相等
        if (!cnts.all { it == cnts[0] }) return -1
        return ret
    }
}

复杂度分析:

  • 时间复杂度:$O(n + C)$ 其中 $n$ 是 $croakOfFrogs$ 字符串的长度,$C$ 是字符集大小,$C$ 为常数 $5$;
  • 空间复杂度:$O(C)$ 计数数组空间。

相似题目:


T3 · 复原 IP 地址(Medium)

题目地址

https://leetcode.cn/problems/restore-ip-addresses/

题目描述

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

  • 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245""192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

题解(回溯)

简单回溯模板题,按照回溯三要素编码即可:

  • 终止条件:index == s.length
  • 路径 path:已选择的片段,我们用 List 记录,再输出结果时再补充分隔符
  • 选择列表:可以选择 1 到 3 个字符,限制条件是不能有前导 0 且数字大小不超过 255。
class Solution {
    fun restoreIpAddresses(s: String): List<String> {
        val ret = LinkedList<String>()
        backtrack(s, 0, LinkedList<String>(), ret)
        return ret
    }

    private fun backtrack(s: String, index: Int, path: LinkedList<String>, result: LinkedList<String>) {
        // 终止条件
        if (index == s.length) {
            // 满足 IPv4 格式
            if (path.size == 4) result.add(path.joinToString("."))
            return
        }
        // 剪枝:已经达到 4 个片段但字符串未结束
        if (path.size == 4) return
        // 剪枝:1 到 3 个字符,但不能有前导 0 和越界
        val maxIndex = if (s[index] == '0') index else Math.min(index + 2, s.length - 1)
        // 枚举选项
        for (toIndex in index..maxIndex) {
            val segment = s.substring(index, toIndex + 1)
            // 剪枝:超过 255 范围
            if (segment.toInt() > 255) return
            // 选择
            path.add(segment)
            // 递归
            backtrack(s, toIndex + 1, path, result)
            // 回溯
            path.removeLast()
        }
    }
}

复杂度分析:

  • 时间复杂度:$O(3^4·n)$ 其中 3 是每一层的最大选择列表;4 是最大片段数,n 是字符串的长度。回溯递归栈的最大深度是 4 层,每一层有 3 种选项,因此一共有 $3^4$ 种子状态,每个子状态最多需要花费 $O(n)$ 时间构造结果字符串;
  • 空间复杂度:$O(4)$ 递归栈空间,不考虑结果数组和路径数组。

相似题目:


T4 · 课程表 III(Hard)

题目地址

https://leetcode.cn/problems/course-schedule-iii/description/

题目描述

这里有 n 门不同的在线课程,按从 1 到 n 编号。给你一个数组 courses ,其中 courses[i] = [durationi, lastDayi] 表示第 i 门课将会 持续 上 durationi 天课,并且必须在不晚于 lastDayi 的时候完成。

你的学期从第 1 天开始。且不能同时修读两门及两门以上的课程。

返回你最多可以修读的课程数目。

题解(排序 + 贪心 + 大顶堆)

这道题可以用常识辅助思考:

  • 如果两门课的 DDL 不同,那么应该优先学 DDL 较早的;

亦可严格证明:设两门课为 c1(t1, d1), c2(t2, d2),且满足 d1 ≤ d2,即 c1 的截止时间较早,则有 4 种上课方案(设学期开始时间为 0):

  • 只上 c1,需要满足 t1 <= d1
  • 只上 c2:需要满足 t2 <= d2
  • 先上 c1 再上 c2,需要满足 t1 + t2 <= d2
  • 先上 c2 再上 c1,需要满足 t2 + t1 <= d1 <= d2

由于 d1 <= d2,因此 「先学习后者,再学习前者」的条件 t2 + t1 <= d1 成立,也说明 「先学习前者,再学习后者」的条件 t2 + t1 <= d2 也成立。但反过来,如果 t1 + t2 <= d2 无法推出 t2 + t1 <= d1 成立。

以上说明先学习截止时间晚的方案不会比先学习截止时间早的方案更优。因此,我们可以先将所有的课程按照截止时间进行升序排序,再依次挑选课程进行学习。

  • 如果两门课的 DDL 相同,那么应该优先学 Duration 较短的;

亦可用类似的方式证明,也很容易直观理解,优先学习时长更短的课程能够减缓时间推进速度,更有利于选出更优的方案。

  • 如果一门课没有足够的时间完成,那么可以尝试战术性淘汰已选择列表中耗时最长课程,给之后的课程留出时间。

这一点比较不好想到,但是编码不难,难的是如何证明 “淘汰已选择列表中耗时最长课程” 的做法是最优的方案,以及如何保证替换淘汰后替换成当前课程后也能够满足截止时间限制。

亦可简单证明:设已选择的前 i - 1 门课程的最优方案为 {t_1、t_2、t_3、…t_{i-1}} 有学习总时长 time,那么对于课程 courses[i] 来说,则有:

  • 如果 time + courses[i][0] ≤ courses[i][1],那么可以进行学习;
  • 否则,我们从已选择列表中寻找出学习时长最长的课程 courses[j],且满足 courses[j][0] > courses[i][0],即该课程的学习时长大于当前课程的时长。那么我们替换这两个课程(每个课程的贡献都是 1 的前提下),一定不会得到更差的方案,且能够减缓时间的推进进度。

最后剩下的问题是如何寻找 “已选择列表中耗时最长课程”,这个用大顶堆很简单。

class Solution {
    fun scheduleCourse(courses: Array<IntArray>): Int {
        // 按照截止时间排序
        Arrays.sort(courses) { c1, c2 ->
            c1[1] - c2[1]
        }
        // 选择列表(大顶堆,按照时长降序)
        val heap = PriorityQueue<IntArray>() { c1, c2 ->
            c2[0] - c1[0]
        }
        var time = 0
        for (course in courses) {
            if (time + course[0] <= course[1]) {
                // 可以选择
                time += course[0]
                heap.offer(course)
            } else if (!heap.isEmpty() && heap.peek()[0] > course[0]) {
                // 无法选择,尝试淘汰并替换耗时最长任务
                time -= heap.poll()[0]
                time += course[0]
                heap.offer(course)
            } // else 无法替换
        }
        // 选择列表
        return heap.size
    }
}

复杂度分析:

  • 时间复杂度:$O(nlgn + n)$ 其中 $n$ 为 $courses$ 数组的长度;
  • 空间复杂度:$O(lgn + n)$ 排序递归栈空间和大顶堆空间。

相似题目:

目录
相关文章
|
监控 安全 大数据
恭喜我们的两家客户,入选住建部智慧水务典型案例!
恭喜我们的两家客户,入选住建部智慧水务典型案例!
187 0
|
双11
报告发布|复盘2021届双11,拼的是“经营力”
编者按: 历经13年演化,双11成为无限竞争的集中公演场,品牌的严酷挑战与最大机遇并存。通过品牌升级、技术创新、经营力重塑三大计划,阿里妈妈在双11助力品牌商家通过精准投入,获得确定回报。 在平台的引领下,双11进入全新“经营力”时代。这让双11不再是生意的终点。那双11又会变成什么呢?
118 0
|
前端开发 搜索推荐 小程序
蚂蚁P10玉伯的产品思考:技术人如何做产品
蚂蚁P10玉伯的产品思考:技术人如何做产品
305 0
|
存储 分布式计算 算法
二本材料专业,干过销售,当过兵,28岁零基础转型大数据开发进百度,很强势!
二本材料专业,干过销售,当过兵,28岁零基础转型大数据开发进百度,很强势!
二本材料专业,干过销售,当过兵,28岁零基础转型大数据开发进百度,很强势!
|
SQL 人工智能 分布式计算
电网工作2年后考研,8面阿里,成功转型大数据开发
电网工作2年后考研,8面阿里,成功转型大数据开发
电网工作2年后考研,8面阿里,成功转型大数据开发
|
人工智能 前端开发 安全
深度解读陈明永最新演讲,OPPO 100亿研发投入背后的战略推演
深度解读陈明永最新演讲,OPPO 100亿研发投入背后的战略推演
254 0
深度解读陈明永最新演讲,OPPO 100亿研发投入背后的战略推演
|
人工智能 运维 搜索推荐
特色小镇怎么做?联想、泛华合作找答案
特色小镇怎么做?联想、泛华合作找答案
151 0
特色小镇怎么做?联想、泛华合作找答案
|
新零售 供应链 前端开发
饿了么彻底“阿里化”改造后,提出一个阿里味的战略——新服务
2018年10月12日,阿里巴巴合并了饿了么与口碑,成立“阿里本地生活服务公司”,过去的一年,阿里巴巴投入巨大成本彻底完成了饿了么的“阿里化”改造,一年后的2019年11月19日,饿了么提出了一个浓烈“阿里味”的全新战略——新服务。
354 0
饿了么彻底“阿里化”改造后,提出一个阿里味的战略——新服务
|
城市大脑
【老文新推】从6000人落户北京谈起:人才评估体系应该多元化
【老文新推】从6000人落户北京谈起:人才评估体系应该多元化
196 0
【老文新推】从6000人落户北京谈起:人才评估体系应该多元化
|
人工智能 编解码 达摩院
为拿下算法 “奥斯卡”,阿里团队设计了一个冠军方案
被誉为计算机视觉领域 “奥斯卡” 的 CVPR 刚刚落下帷幕,2021 年首届 “新内容 新交互” 全球视频云创新挑战赛正火热进行中,这两场大赛都不约而同地将关注点放在了视频目标分割领域,本文将详细分享来自阿里达摩院的团队在 CVPR DAVIS 视频目标分割比赛夺冠背后的技术经验,为本届大赛参赛选手提供 “他山之石”。
为拿下算法 “奥斯卡”,阿里团队设计了一个冠军方案