[LeetCode] 九坤-03. 数字默契考验
一、题目
某数学兴趣小组有 N 位同学,编号为 0 ~ N-1,老师提议举行一个数字默契小测试:首先每位同学想出一个数字,按同学编号存于数组 numbers。每位同学可以选择将自己的数字进行放大操作,每次在以下操作中任选一种(放大操作不限次数,可以不操作):
将自己的数字乘以 2
将自己的数字乘以 3
若最终所有同学可以通过操作得到相等数字,则返回所有同学的最少操作次数总数;否则请返回 -1。
示例 1:
输入:numbers = [50, 75, 100]
输出:5
解释:
numbers[0] * 2 * 3 = 300 操作两次;
numbers[1] * 2 * 2 = 300 操作两次;
numbers[2] * 3 = 300 操作一次。共计操作五次。
示例 2:
输入:numbers = [10, 14]
输出:-1
解释:无法通过操作得到相同数字。
提示:
- 1 <= numbers.length <= 10^5
- 1 <= numbers[i] <= 10^9
二、题解
- 任何一个数字都可以分解成 x ∗ 2 m ∗ 3 n x*2^{m}*3^{n} x∗2m∗3n;
- 假如
n
u
m
b
e
r
[
i
]
number[i]
number[i]和
n
u
m
b
e
r
[
j
]
number[j]
number[j]可以通过乘以2或者乘以3变成相等的数字
n
u
m
[
k
]
num[k]
num[k],根据
1.
有:
n u m b e r [ i ] = n u m [ i ] ∗ 2 m i ∗ 3 n i number[i] = num[i]*2^{mi}*3^{ni} number[i]=num[i]∗2mi∗3ni、 n u m b e r [ j ] = n u m [ j ] ∗ 2 m j ∗ 3 n j number[j] = num[j]*2^{mj}*3^{nj} number[j]=num[j]∗2mj∗3nj。
那么有: n u m [ k ] = n u m [ i ] ∗ 2 m i ∗ 3 n i ∗ 2 x i ∗ 3 x j = n u m [ j ] ∗ 2 m j ∗ 3 n j ∗ 2 x j ∗ 3 x j num[k]=num[i]*2^{mi}*3^{ni}*2^{xi}*3^{xj}=num[j]*2^{mj}*3^{nj}*2^{xj}*3^{xj} num[k]=num[i]∗2mi∗3ni∗2xi∗3xj=num[j]∗2mj∗3nj∗2xj∗3xj,
由于 n u m [ i ] num[i] num[i]和 n u m [ j ] num[j] num[j]都与2、3互质,因此为了满足上式,需要保证 n u m [ i ] = n u m [ j ] num[i]=num[j] num[i]=num[j]。 - 因此,我们可以将numbers中的所有数字分解为
n
u
m
[
i
]
∗
2
m
i
∗
3
n
i
num[i]*2^{mi}*3^{ni}
num[i]∗2mi∗3ni的形式,然后判断
n
u
m
[
0
]
,
n
u
m
[
1
]
.
.
.
n
u
m
[
n
−
1
]
num[0],num[1]...num[n-1]
num[0],num[1]...num[n−1]是否相等,如果不相等返回
−
1
-1
−1。如果相等,再统计
2
m
∗
3
n
2^{m}*3^{n}
2m∗3n中2的幂次最大值
m
a
x
m
max_m
maxm和3的幂次最大值
m
a
x
n
max_n
maxn,需要乘以2或者乘以3的总次数就是各个数字的2的幂次变成
m
a
x
m
max_m
maxm和3的幂次变成
m
a
x
n
max_n
maxn的次数之和。
具体请看下方代码
三、代码
class Solution {
public:
// 把一个数字 分成 x *2*2*2*...*3*3*3, 返回{num[i], 2的幂次, 3的幂次}
tuple<int, int, int> getAns(int num){
int x = num;
int cnt_2 = 0;
int cnt_3 = 0;
while(x%2==0){
x/=2;
cnt_2 ++;
}
while(x%3==0){
x/=3;
cnt_3 ++;
}
return {x, cnt_2, cnt_3};
}
int minOperations(vector<int>& numbers) {
int ans = 0;
int n = numbers.size();
int a,b,c;
vector<array<int, 3>> nums(n);
for(int i=0; i<n; i++){
tie(nums[i][0],nums[i][1],nums[i][2]) = getAns(numbers[i]);
}
for(int i=0; i<n-1; i++){
if(nums[i][0]!=nums[i+1][0]){
return -1;
}
}
int max_cnt_2 = 0;
int max_cnt_3 = 0;
for(int i=0; i<n; i++){
max_cnt_2 = max(max_cnt_2, nums[i][1]);
max_cnt_3 = max(max_cnt_3, nums[i][2]);
}
for(int i=0; i<n; i++){
ans += max_cnt_2 - nums[i][1];
ans += max_cnt_3 - nums[i][2];
}
return ans;
}
};
- 时间复杂度:O(n*log(n));
- 空间复杂度:O(n*log(n));