车企选择
今天逛某职场 App 时,无意间看到一篇寻求 offer 抉择意见的帖子:
这位同学刚从加班闻名(但 CEO 强调既学华为狼性,也学华为分配)的理想汽车离职。
经过了 6 轮面试,收到了小米 offer,但目前纠结是否要去。
不好的地方,入职前面试官就明说了,基本上每天都 10 点后下班,而且候选人也担心小米汽车不靠谱。
好的地方,待遇给的是真心不错。
连从理想汽车跳槽出来的网友都觉得不错,那说明小米汽车的待遇确实是有竞争力的。
但评论区有不少小米员工则现身说法,表达的都是「劝退」意见:
有同学强调,实际情况下班都是晚上 10:30 起步,而且入职时宣称的弹性工作时间,只弹了下班时间 🤣
还有同学指出,小米内卷严重,期权不合理,而且小米汽车只是试水产品,会有失败风险。
最终,这位同学"听劝"了,决定放弃小米 offer,入职大众中国。
但这些都是网友在去年 10 月给出的意见了,现在小米汽车上市交付已经有段时间,基本上是空前成功,热度不减,一车难求。
按照常规理解,小米汽车的年终奖应该不会低,也不知道那位楼主有没有拍断大腿。
...
回归主线。
来一道和「新能源车企」相关的算法原题。
题目描述
平台:LeetCode
题号:1775
给你两个长度可能不等的整数数组 nums1
和 nums2
。两个数组中的所有值都在 1
到 6
之间(包含 1
和 6
)。
每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 1
到 6
之间 任意 的值(包含 1
和 6
)。
请你返回使 nums1
中所有数的和与 nums2
中所有数的和相等的最少操作次数。如果无法使两个数组的和相等,请返回 -1
。
示例 1:
输入:nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums2[0] 变为 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[5] 变为 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[2] 变为 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。
示例 2:
输入:nums1 = [1,1,1,1,1,1,1], nums2 = [6]
输出:-1
解释:没有办法减少 nums1 的和或者增加 nums2 的和使二者相等。
示例 3:
输入:nums1 = [6,6], nums2 = [1]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums1[0] 变为 2 。 nums1 = [2,6], nums2 = [1] 。
- 将 nums1[1] 变为 2 。 nums1 = [2,2], nums2 = [1] 。
- 将 nums2[0] 变为 4 。 nums1 = [2,2], nums2 = [4] 。
提示:
枚举 + 贪心 + 数学
令 nums1
的长度为 n
,nums2
的长度为 m
,根据题意两数组的值域分别为 和 ,可分别视为数轴上的两条线段。
为了方便,我们人为固定 ,若不满足则交换两数组,返回 minOperations(nums2, nums1)
即可。
先来考虑无解的情况:当 时,说明两线段不重合,必然无法通过变换使得总和相等,直接返回 -1
。
由于 的范围为 ,且 的值域大小 ,因此我们可以通过枚举最终目标和 x
(两线段的重合部分)来做,枚举范围不超过 。
于是问题转换为:对于一个原总和为 sum
的数组 nums
而言,按照题目的变换规则,至少经过多少次变换,才能将其总和变为 x
。
根据原总和 sum
和目标结果 x
的大小关系进行分情况讨论(将两者差值绝对值记为 d
):
-
当 时,对于原数为 的数而言,其能变为不超过 的任意数。
例如 能够变化为 中的任意数,即单个数值 最多能够抵消 个差值,不失一般性的可概括为原数为 所能抵消的差值为 。
因此,我们贪心的使用较大数进行变换(从 往 枚举
i
),对于每个数值i
而言,其所能提供的个数为 。 -
当 时,同理,原数为 所能提供的最大抵消数为 ,因此我们贪心使用较小数进行变换(从 往 枚举
i
),对于每个数值i
而言,其所能提供的个数为 。
如此一来,我们通过枚举两线段重合点 x
,复杂度为 ,并通过复杂度为 的数学方法来得知将两原数组总和变为 x
所需要的操作次数 cnt
,在所有的 cnt
取最小值即是答案。整体计算量为 ,可以过。
Java 代码:
class Solution {
int[] c1 = new int[10], c2 = new int[10];
int s1, s2;
public int minOperations(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
if (n > m) return minOperations(nums2, nums1);
if (m > 6 * n) return -1;
for (int x : nums1) {
c1[x]++; s1 += x;
}
for (int x : nums2) {
c2[x]++; s2 += x;
}
int ans = n + m;
for (int i = m; i <= 6 * n; i++) ans = Math.min(ans, getCnt(c1, s1, i) + getCnt(c2, s2, i));
return ans;
}
int getCnt(int[] cnts, int sum, int x) {
int ans = 0;
if (sum > x) {
for (int i = 6, d = sum - x; i >= 2 && d > 0; i--) {
int c = Math.min((int) Math.ceil(d * 1.0 / (i - 1)), cnts[i]);
ans += c; d -= c * (i - 1);
}
} else if (sum < x) {
for (int i = 1, d = x - sum; i <= 5 && d > 0; i++) {
int c = Math.min((int) Math.ceil(d * 1.0 / (6 - i)), cnts[i]);
ans += c; d -= c * (6 - i);
}
}
return ans;
}
}
C++ 代码:
class Solution {
public:
int c1[10], c2[10];
int s1, s2;
int minOperations(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
if (n > m) return minOperations(nums2, nums1);
if (m > 6 * n) return -1;
for (int x : nums1) {
c1[x]++; s1 += x;
}
for (int x : nums2) {
c2[x]++; s2 += x;
}
int ans = n + m;
for (int i = m; i <= 6 * n; i++) {
ans = min(ans, getCnt(c1, s1, i) + getCnt(c2, s2, i));
}
return ans;
}
int getCnt(int cnts[], int sum, int x) {
int ans = 0;
if (sum > x) {
for (int i = 6, d = sum - x; i >= 2 && d > 0; i--) {
int c = min((int) ceil(d * 1.0 / (i - 1)), cnts[i]);
ans += c; d -= c * (i - 1);
}
} else if (sum < x) {
for (int i = 1, d = x - sum; i <= 5 && d > 0; i++) {
int c = min((int) ceil(d * 1.0 / (6 - i)), cnts[i]);
ans += c; d -= c * (6 - i);
}
}
return ans;
}
};
Python 代码:
class Solution:
def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
n, m = len(nums1), len(nums2)
if n > m:
return self.minOperations(nums2, nums1)
if m > 6 * n:
return -1
c1, c2 = Counter(nums1), Counter(nums2)
s1, s2 = sum(nums1), sum(nums2)
def getCnt(cnts, tot, x):
ans = 0
if tot > x:
d = tot - x
for i in range(6, 1, -1):
if d <= 0:
break
c = min(math.ceil(d / (i - 1)), cnts[i])
ans, d = ans + c, d - c * (i - 1)
elif tot < x:
d = x - tot
for i in range(1, 6):
if d <= 0:
break
c = min(math.ceil(d / (6 - i)), cnts[i])
ans, d = ans + c, d - c * (6 - i)
return ans
ans = n + m
for i in range(m, 6 * n + 1):
ans = min(ans, getCnt(c1, s1, i) + getCnt(c2, s2, i))
return ans
-
时间复杂度: ,其中 为 的值域大小 -
空间复杂度:
最后
给大伙通知一下 📢 :
全网最低价 LeetCode 会员目前仍可用!!!
📅 年度会员:有效期加赠两个月!!; 季度会员:有效期加赠两周!!
🧧 年度会员:获 66.66 现金红包!!; 季度会员:获 22.22 现金红包!!
🎁 年度会员:参与当月丰厚专属实物抽奖(中奖率 > 30%)!!
专属链接:leetcode.cn/premium/?promoChannel=acoier
我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻。
欢迎关注,明天见。
更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉