特斯拉产品研发创新中心 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)$ 排序递归栈空间和大顶堆空间。

相似题目:

目录
相关文章
|
存储 运维 监控
因洞察,生价值 | 数据洞察创新挑战赛·线下实践沙龙-北京站,等你参加
7月15日14:00-16:30,数据洞察创新挑战赛·线下实践沙龙-北京,等你参加
8880 2
因洞察,生价值 | 数据洞察创新挑战赛·线下实践沙龙-北京站,等你参加
《阿里云总监课第五期第六节:研发挑战 - 研发过程中挑战》电子版地址
阿里云总监课第五期第六节:研发挑战 - 研发过程中挑战
74 0
《阿里云总监课第五期第六节:研发挑战 - 研发过程中挑战》电子版地址
|
SQL 运维 搜索推荐
客户案例:大淘系模型建设实践(二)| 学习笔记
快速学习客户案例:大淘系模型建设实践。
客户案例:大淘系模型建设实践(二)| 学习笔记
|
数据管理 数据建模 BI
客户案例:大淘系模型建设实践(一)| 学习笔记
快速学习客户案例:大淘系模型建设实践。
客户案例:大淘系模型建设实践(一)| 学习笔记
《研发效能36计:研发效能提升之路,从天文学的演进说起》电子版地址
研发效能36计:研发效能提升之路,从天文学的演进说起
152 0
《研发效能36计:研发效能提升之路,从天文学的演进说起》电子版地址
|
监控 安全 Cloud Native
阿里产品专家:高情商的技术人,如何做沟通?
不愿沟通是固执,不会沟通是傻瓜,不敢沟通是奴隶。——德拉蒙德
阿里产品专家:高情商的技术人,如何做沟通?
|
开发者
阿里云开发者能力评测团队排位赛圆满收官!
尊敬的开发者,为期三周的阿里云开发者能力评测团队排位赛圆满收官了!相信,通过此次活动,一定有不少开发者在技能知识储备、技术交友以及团队组织方面的能力又有所收获。
阿里云开发者能力评测团队排位赛圆满收官!
|
弹性计算 运维 Kubernetes
攻坚、变革、创新 | 阿里研究员千字细说阿里云的十年“计算”重构史
听阿里巴巴集团研究员、阿里云智能弹性计算负责人张献涛,阿里云智能资深技术专家、阿里云容器技术负责人易立,还原阿里云十年“计算”重构史。
攻坚、变革、创新 | 阿里研究员千字细说阿里云的十年“计算”重构史
|
人工智能 运维 Cloud Native
一图剧透!阿里巴巴研发效能峰会核心看点速览
6月12日-13日 阿里巴巴内部研发效能峰会首次对外直播! 7大论坛,35个议题,1300分钟技术干货! 39位技术大咖,4万阿里工程师,邀你共享研发效能盛宴!
2523 0
一图剧透!阿里巴巴研发效能峰会核心看点速览
|
人工智能 Kubernetes Cloud Native
开发者如何get技术趋势,实现成长破局?——MVP线上峰会
使众人行,你需要拥有的管理思维;数据库那些事儿,讲讲创新实战;AIoT新技术新场景实战,说干就干!未来已来!云原生战“疫”实操!
961 0
开发者如何get技术趋势,实现成长破局?——MVP线上峰会

热门文章

最新文章