[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

二、题解

  1. 任何一个数字都可以分解成 x ∗ 2 m ∗ 3 n x*2^{m}*3^{n} x2m3n
  2. 假如 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]2mi3ni 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]2mj3nj
    那么有: 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]2mi3ni2xi3xj=num[j]2mj3nj2xj3xj
    由于 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]
  3. 因此,我们可以将numbers中的所有数字分解为 n u m [ i ] ∗ 2 m i ∗ 3 n i num[i]*2^{mi}*3^{ni} num[i]2mi3ni的形式,然后判断 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[n1]是否相等,如果不相等返回 − 1 -1 1。如果相等,再统计 2 m ∗ 3 n 2^{m}*3^{n} 2m3n中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));

posted on 2022-08-22 20:59  刘好念  阅读(22)  评论(0编辑  收藏  举报  来源