查找整数的算法,使其数字的乘积为N.

时间:2014-01-28 10:58:10

标签: algorithm data-structures

我在一个挑战中发现了这个问题。

问题是我们得到一个整数N,我们需要找到数字乘积为N

的最小数字X.

我的方法是用单个数字查找素数 例如10倍数是2.5 对于100倍数是2,2,5,5

  • 现在我需要找到最小的整数,所以我算不上2和3的
  • 如果有三个2,那么我用一个8
  • 替换三个2
  • 如果有两个2,那么我将用一个4
  • 替换两个2
  • 如果有两个3,那么我将用一个9
  • 替换两个3

你们能想到更好的算法吗?

int getNumber(int n) {

    int temp = n;
    int a[4] ={2,3,5,7};
    std::string str;
    do
    {
        for(int i=0;i<4;++i)
        {
            int val = temp%a[i];
            if(val ==0)
            {
                char s[260];
                sprintf(s,"%d",a[i]);
                str += s;
                temp /=a[i];
                break;
            }

        }

    }while(temp>1);
    char newStr[260];
    int countof2=0,countof3=0;
    for(int i=0;i<str.length();++i)
    {
        if(str[i]=='2')
                ++countof2;
        if(str[i]=='3')
            ++countof3;
    }
    bool bFlag=false;
    int indexNew=0;
        if(countof2 >= 3)
        {

            int count =0;
            for(int index=0;index<str.length();++index)
            {
                if(str[index]=='2'&& count<3)
                    ++count;
                else
                {
                    newStr[indexNew]= str[index];
                    ++indexNew;
                }
            }
            newStr[indexNew]='8';
            bFlag=true;
        }
        else if(countof2 >=2)
        {
            newStr[indexNew++]='4';
            int count =0;
            for(int index=0;index<str.length();++index)
            {
                if(str[index]=='2'&& count<2)
                    ++count;
                else
                {
                    newStr[indexNew]= str[index];
                    ++indexNew;
                }
            }
            bFlag=true;
        }
        else if(countof3 >=2)
        {
            int count =0;
            for(int index=0;index<str.length();++index)
            {
                if(str[index]=='3'&& count<2)
                    ++count;
                else
                {
                    newStr[indexNew]= str[index];
                    ++indexNew;
                }
            }
            newStr[indexNew]='9';
            bFlag=true;
        }

        newStr[++indexNew]= '\0';
        int val=0;
        if(bFlag)
         val = atoi(newStr);
        else
         val = atoi(str.c_str());

    return val;
}

5 个答案:

答案 0 :(得分:3)

我没有用(2,2,2) - > 8,(3,3) - > 9等寻找奇怪的解决方案,而是采用直接的解决方案(忘记素数,直接转到所有位):

for (d = 9; d > 1; d--)
    while (n % d == 0) {
        n /= d;
        list.addDigit(d);
    }
if (n != 1) print("no such number"); else print(reverse(list));

答案 1 :(得分:1)

如果存在D的素数除数N such that D>=10,则无法解决。

你的方法几乎是正确的。唯一的评论是6 = 2*3 最优策略是将许多数字转换为一个数字,如2*2*2->8,如果存在许多变换变体,请选择那些给出最小数字的变体。

按以下顺序执行以下步骤:

1)将所有(2,2,2)三元组转换为8。

2)(2,2) - > 4

3)(2,3) - > 6

4)(3,3) - > 9

将所有数字放入一个数组并对其进行排序。请注意,您还必须输入结果数组,如5,7,剩余的2和3。

输出排序数组 - 它将回答您的问题。

示例 N = 96 = 2 * 2 * 2 * 2 * 2 * 3 = 8 * 4 * 3。排序(8,4,3) - 3,4,8。答案是348。

答案 2 :(得分:0)

假设D = N的所有除数(不是必要的素数)的集合。然后可以计算dp(d) - 数字的最小长度,数字乘积恰好d为D中的所有d。重建答案,一可以找到最小的x,例如dp(d / x)= dp(x)-1,从d = N开始,直到d = 1.该算法产生最短和最小的lexigraph数。因此,这是正确的。 上面答案中描述的贪婪算法是不正确的。它产生348,N = 96,而正确的答案是268。 这是我的代码。

import java.util.*;

public class Main {
        static Map<Integer, Integer> dp;

        public static void main(String[] args) {
                Scanner in = new Scanner(System.in);
                int N = in.nextInt();
                System.out.println(getNumber(N));
        }

        static int getNumber(int N) {
                if (N == 1)
                        return 1;
                dp = new HashMap<>();
                if (getDp(N) == Integer.MAX_VALUE)
                        return -1;
                String result = reconstruct(N);
                return Integer.parseInt(result);
        }

        static int getDp(int N) {
                if (N == 1)
                        return 0;
                if (dp.containsKey(N))
                        return dp.get(N);
                int best = Integer.MAX_VALUE;
                for (int digit = 2; digit <= 9; digit++)
                        if (N % digit == 0)
                                best = Math.min(best, getDp(N / digit) + 1);
                dp.put(N, best);
                return best;
        }

        static String reconstruct(int N) {
                if (N == 1)
                        return "";
                int minDigit = 2;
                while (N % minDigit != 0 || getDp(N / minDigit) + 1 != getDp(N))
                        minDigit++;
                String result = reconstruct(N / minDigit);
                return Integer.toString(minDigit) + result;
        }
}

答案 3 :(得分:0)

查找素数除数及其{2,3,5,7}的幂。如果在连续除法后仍然保持大于1,那么就没有解,因为余数是素数而不能由{1-9}的乘法得出。现在唯一剩下的就是结合2&amp; 3这样的组合是最小的。

通过以下方式找到最低要求: -

1. Combine all k (2,2,2) =>  k 8's
2. all m (2,2) => m 4's
3. all x (2,3) => x 6's
4. all y (3,3) => y 9's

使用排序在O(logN)中获得最小解,其中N是输入数。

答案 4 :(得分:0)

这里的解决方案呈指数级增长,但很容易使用动态编程技术成为伪多项式。

我将从一个递归开始,我们将从最小可能的除数开始并分成子问题。它将返回最终除法的值并保存最小值。

编辑:只是添加它只适用于非素数输入

int getMinDigit(int N, int P) {
    if(N == 1) {
        return P;
    }

    int div = 2;
    int min = INT_MAX;
    do {
        //checking if its divisible
        if(N%div == 0) {
            //get the other multiplier
            int Q = N/div;

            //we are done with our recursion
            if(Q < div)
                break;

            //getting the sub problem resolved
            int value = getMinDigit(Q, 10*P + div);
            min = min<value? min: value;
        }

        div++;
    } while(true);

    return min;
}

此算法的时间复杂度是指数级的。我们可以使用DP减少伪多项式的时间复杂度。

简单地以自下而上的方式计算子问题,或者每次调用memonize解决方案。像P(6)P(9)

P(36)
|
P(2, P(18))
|    |
|    P(2, P(9)) (matching sub problem)
|    P(3, P(6))
P(3, P(12))
|    |
|    P(2, P(6))
|    P(3, P(4))
P(4, P(9)) <-- this is your solution
|    |
|    P(3, P(3));    
P(6, P(6))
|    |
|    P(2, P(3))
(x) break;
P(9, P(4))