前端工程师的 LeetCode 之旅 - 夜喵专场(20)

1,025 阅读4分钟
01 根据数字二进制下 1 的数目排序 题目描述【Easy】 给你一个整数数组 arr 。请将数组中的元素按照其二进制表示中数字 1 的数目升序排列。 如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。

解决本道题目首先需要求解出一个整数二进制表示法中 1 的个数。

朴实的解法:将整数转化为二进制字符串,再统计 1 的个数

更加效率的解法: 利用位运算的特性去掉转化的过程并且减少迭代的次数

最后通过 JavaScript 中 sort 方法进行多条件排序,即可解题。

02         实现每隔 n 个顾客打折 题目描述【Medium】 超市里正在举行打折活动,每隔 n 个顾客会得到 discount 的折扣。超市里有一些商品,第 i 种商品为 products[i] 且每件商品的价格为 prices[i]。 结账系统会统计顾客的数目,每隔 n 个顾客结账时,该顾客的账单都会打折,折扣为 discount,然后系统会重新开始计数。 顾客会购买一些商品,product[i] 是顾客购买的第 i 种商品,amount[i] 是对应的购买该种商品的数目。 请实现 Cashier 类。

这道题目给的条件相对比较多,需要仔细阅读条件,注意 几个变量之间的下标关系,具体实现代码如下:

03   包含所有三种字符的子字符串数目 题目描述【Medium】 给你一个字符串 S ,它只包含三种字符 a,b,c 。请返回 a,b 和 c 都至少出现过一次的子字符串的数目。

通过暴力枚举,可以在 O(n^2) 的时间复杂度内统计合法的子串。

对于字符串 [0, i],如果 [0, j] 为合法字串,那么 [0, j+1] 必然也为合法字串。

利用上述特性,可以减少内循环的次数,具体实现代码如下:

但是,本道题 O(n^2) 的时间复杂度是没法 AC 的。

从上述暴力枚举的过程中,可以发现只要找到最小的合法字串,其他包含该字串的数目很容易计算。而对于任意一个子串,无非就是开始下标和结束下标,那么就可以采用双指针技巧,将时间复杂度降低为 O(n)

再利用哈希表记录当前子串中字符的状态,从而减少子串验证合法性的时间复杂度。

04             有效的快递序列数目 题目描述【Hard】 给你 n 笔订单,每笔订单都需要快递服务。请你统计所有有效的收件/配送 序列的数目,请确保第 i 个物品的配送服务 delivery(i) 总是在其收件服务 pickup(i) 之后。 由于答案可能很大,请返回答案对 10^9 + 7 取余的结果。

这是一道动态规划的题目,可以定义 dp[i] 表示 i 笔订单有效序列的个数

由上述题目中给出的信息,可以很容易知道:

  • dp[0] = 0

  • dp[1] = 1

那么当 i = 2 时,可以基于 i = 1 进行如下操作得到所有有效序列。

第一种情况:将 P2D2 合并在一起插入到前一个状态中

第二种情况:将 P2D2 分开插入,保证 P2 在 D2 之前。

根据上述推导过程,可以得到如下状态转移方程:

由推导公式,可以发现下一个状态只与前一个状态有关系,那么就没必要利用数组记录无关的状态,时间复杂度可以降低为 O(1)。

最后千万不要忘记对结果取余哦。

05       精彩回顾

你点的每个赞,我都认真当成了喜欢