Algorithm 将整数表示为一系列乘法器

Algorithm 将整数表示为一系列乘法器,algorithm,language-agnostic,Algorithm,Language Agnostic,向下滚动查看最新编辑,我将所有文本都留在这里,这样我就不会使这个问题迄今为止收到的答复无效 我有一个脑筋急转弯,我想得到一个解决方案,我试图解决这个问题,但由于我在数学上并没有那么高的平均水平(也就是说,我认为我非常接近平均水平),我似乎无法理解这一点 问题是:给定的数字x应该被分成一系列的乘数,其中每个乘数=y,将y存储到乘数,然后x=x-y 当x

向下滚动查看最新编辑,我将所有文本都留在这里,这样我就不会使这个问题迄今为止收到的答复无效


我有一个脑筋急转弯,我想得到一个解决方案,我试图解决这个问题,但由于我在数学上并没有那么高的平均水平(也就是说,我认为我非常接近平均水平),我似乎无法理解这一点

问题是:给定的数字
x
应该被分成一系列的
乘数
,其中每个
乘数=y
,将
y
存储到
乘数
,然后
x=x-y
  • x
    时,将
    x
    存储到
    乘法器
  • 显然,这不起作用,我还尝试单独存储“剩余”部分,并在所有其他内容之后添加,但这也不起作用。我认为我的主要问题是,我试图以一种过于复杂的方式来思考这个问题,而解决方案是显而易见和简单的

    重申一下,此算法应具有以下限制:

    • 必须使用64位长
    • 必须返回一个32位整数的数组(…嗯,也可以使用短整数)
    • 虽然支持有符号的数字(+和-)会很好,但如果它有助于完成任务,则必须只支持无符号数字
    当我用Java做这件事的时候,我更愿意把任何可能的代码示例作为伪代码,我特别不想要现成的答案,我只需要一个轻推(好吧,更强烈的刺激),这样我至少可以自己解决部分问题。提前谢谢

    编辑:进一步澄清 为了避免混淆,我想我应该改写一下:

    • 结果数组中的每个整数都应小于或等于y,包括最后一个数字
    • 是的,最后一个数字只是一个神奇的数字
    • 不,这不是模数,因为在大多数情况下,第二个数会大于y
    • 是的,大多数可用数字都有多个答案,但是我正在寻找数学运算量最少的答案。就我的逻辑而言,这意味着找到尽可能大的乘数的最大数量,例如
      x=1000000,y=100
      100*100*100
      ,尽管
      10*10*10*10*10
      在数学上同样正确
    到目前为止,我需要仔细考虑给出的答案,但是如果你有什么要补充的,请补充!我非常感谢你们对这件事的关注,谢谢你们

    编辑2:更多解释+赏金 好吧,看来我在这里的目标就是不能像我想象的那样实现。我对我的目标太模糊了,在考虑了一下之后,我决定把我想要做的全部告诉你,看看你能想出什么

    我最初的目标是提出一种特殊的方法,将1..n个大整数(也称为long)打包在一起,使它们的字符串表示形式明显短于写入实际数字。假设10、10^6和1000000的倍数是相同的,但是表示的字符长度却不同

    为此,我想以某种方式组合这些数字,因为预计这些数字彼此有点接近。首先,我认为将
    100、121、282
    表示为
    100+21+161
    可能是一种方法,但字符串长度的节省充其量是可以忽略的,如果数字之间的距离不是很近,那么效果就不太好。基本上我想要超过10%

    所以我想出了一个主意,如果我用一个公共属性,比如一个乘法器,把这些数字分组,然后把剩下的数字除以各个分量,我就可以把它们表示成一个字符串了。这就是问题所在,例如,我认为1000000和100000可以表示为10^(5|6),但由于我的目标用法的上下文,这有点太离谱了:

    上下文是Web。特定的RESTful URL:s。这就是为什么我提到考虑使用64个字符(网络安全的字母数字非保留字符,然后是一些字符),因为那时我可以创建看似随机的URL,这些URL可以解压为表示一组id号的整数列表。在这一点上,我想创建一个类似于base 64的数字系统来表示基数为10/2的数字,但由于我不是一个数学天才,因此除了这一点,我不知道如何做到这一点

    赏金 现在,我已经写了整个故事(很抱歉,这是一个很长的故事),我开始悬赏这个问题。关于前面指定的首选算法的所有要求仍然有效。我还想说,我已经很感激迄今为止我收到的所有答案,我喜欢被证明是错误的,如果它以你们这样的方式做的话

    结论 好吧,赏金现在已经给了。我将一些评论散布到回应中,主要是为了将来的参考和我自己,如果你认为我们应该能够在多个答案中传播,你也可以查看我关于传播赏金的建议,这与这个问题相关


    感谢大家抽出时间回答
    /
    为整数除法(整数),
    %
    为模

    int result[3];
    
    result[0] = y;
    result[1] = x / y;
    result[2] = x % y;
    

    就像我在上面的评论一样,我不确定我是否完全理解这个问题。但是假设整数(n和给定的y),这应该适用于您所述的情况:

    multipliers[0] = n / y;
    multipliers[1] = y;
    addedNumber = n % y;
    

    只需设置x:=x/n,其中n是小于x和y的最大数。当您以x结束时,请在最终解释后编辑:

    我认为base64是最好的解决方案,因为有处理它的标准函数,而这种想法的变体并没有带来太多改进。这里的其他人对此作出了更详细的回答

    关于最初的问题,虽然该准则有效,但不能保证
    shortest_output = {}
    
    foreach (int R = 0; R <= X; R++) {
        // iteration over possible remainders
        // check if the rest of X can be decomposed into multipliers
        newX = X - R;
        output = {};
    
        while (newX > Y) {
           int i;
           for (i = Y; i > 1; i--) {
               if ( newX  % i == 0) { // found a divider
               output.append(i);
               newX  = newX /i;  
               break;
               }
           }
    
           if (i == 1) { // no dividers <= Y
              break;
           }
        }
        if (newX != 1) {
            // couldn't find dividers with no remainder
            output.clear();
        }
        else {
            output.append(R);
                if (output.length() < shortest_output.length()) {
                     shortest_output = output;
                }
        }
    }
    
    int[] IDs;
    IDs.sort() // So IDs[i] is always smaller or equal to IDs[i-1].
    
    string url = Base64Encode(IDs[0]);
    
    for (int i = 1; i < IDs.length; i++) {
      url += "," + Base64Encode(IDs[i-1] - IDs[i]);
    }
    
    public final class PrimeNumberException extends Exception {
    
        private final long primeNumber;
    
        public PrimeNumberException(long x) {
            primeNumber = x;
        }
    
        public long getPrimeNumber() {
            return primeNumber;
        }
    }
    
    public static Long[] decompose(long x, long y) {
        try {
            final ArrayList<Long> operands = new ArrayList<Long>(1000);
            final long rest = x % y;
            // Extract the rest so the reminder is divisible by y
            final long newX = x - rest;
            // Go into recursion, actually it's a tail recursion
            recDivide(newX, y, operands);            
        } catch (PrimeNumberException e) {
            // return new Long[0];
            // or do whatever you like, for example
            operands.add(e.getPrimeNumber());
        } finally {
            // Add the reminder to the array
            operands.add(rest);
            return operands.toArray(new Long[operands.size()]);
        }
    }
    
    // The recursive method
    private static void recDivide(long x, long y, ArrayList<Long> operands)
        throws PrimeNumberException {
        while ((x > y) && (y != 1)) {
            if (x % y == 0) {
                final long rest = x / y;
                // Since y is a divisor add it to the list of operands
                operands.add(y);
                if (rest <= y) {
                    // the rest is smaller than y, we're finished
                    operands.add(rest);
                }
                // go in recursion
                x = rest;
            } else {
                // if the value x isn't divisible by y decrement y so you'll find a 
                // divisor eventually
                if (--y == 1) {
                    throw new PrimeNumberException(x);
                }
            }
        }
    }
    
    public static Long[] decompose(long x, long y) {
        final ArrayList<Long> operands = new ArrayList<Long>();
        final long rest = x % y;
        // Extract the rest so the reminder is divisible by y
        final long newX = x - rest;
        // Go into recursion, actually it's a tail recursion
        recDivide(newX, y, operands);
        // Add the reminder to the array
        operands.add(rest);
        return operands.toArray(new Long[operands.size()]);
    }
    
    // The recursive method
    private static void recDivide(long newX, long y, ArrayList<Long> operands) {
        long x = newX;
        if (x % y == 0) {
            final long rest = x / y;
            // Since y is a divisor add it to the list of operands
            operands.add(y);
            if (rest <= y) {
                // the rest is smaller than y, we're finished
                operands.add(rest);
            } else {
                // the rest can still be divided, go one level deeper in recursion
                recDivide(rest, y, operands);
            }
        } else {
            // if the value x isn't divisible by y decrement y so you'll find a divisor    
            // eventually
            recDivide(x, y-1, operands);
        }
    }
    
                             0 to
    18,446,744,073,709,551,616
    
    -9,223,372,036,854,775,808 to
     9,223,372,036,854,775,807
    
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    abcdefghijklmnopqrstuvwxyz
    0123456789$-_.+!*'(),
    
    Range (bytes)  Chars  Base64 chars  Compression ratio
    -------------  -----  ------------  -----------------
         < 10 (1)      1       2             -100%
        < 100 (1)      2       2                0%
       < 1000 (2)      3       3                0%
       < 10^4 (2)      4       3               25%
       < 10^5 (3)      5       4               20%
       < 10^6 (3)      6       4               33%
       < 10^7 (3)      7       4               42%
       < 10^8 (4)      8       6               25%
       < 10^9 (4)      9       6               33%
      < 10^10 (5)     10       7               30%
      < 10^11 (5)     11       7               36%
      < 10^12 (5)     12       7               41%
      < 10^13 (6)     13       8               38%
      < 10^14 (6)     14       8               42%
      < 10^15 (7)     15      10               33%
      < 10^16 (7)     16      10               37%
      < 10^17 (8)     17      11               35%
      < 10^18 (8)     18      11               38%
      < 10^19 (8)     19      11               42%
      <  2^64 (8)     20      11               45%
    
    >>> import time
    >>> def test():
    ...     before = time.time()
    ...     print factor(2**32-1, 256)
    ...     print time.time()-before
    ...
    >>> test()
    [254, 232, 215, 113, 3, 15]
    1.68499994278
    >>> 254*232*215*113*3+15
    4294967295L
    
    def factor(x, y):
        # y should be smaller than x. If x=y then {y, 1, 0} is the best solution
        assert(x > y)
    
        best_output = []
    
        # try all possible remainders from 0 to y 
        for remainder in xrange(y+1):
            output = []
            composite = x - remainder
            factors = getFactors(composite)
    
            # check if any factor is larger than y
            bad_remainder = False
            for n in factors.iterkeys():
                if n > y: 
                    bad_remainder = True
                    break
            if bad_remainder: continue
    
            # make the best factors
            while True:
                results = largestFactors(factors, y)
                if results == None: break
                output += [results[0]]
                factors = results[1]
    
            # store the best output
            output = output + [remainder]
            if len(best_output) == 0 or len(output) < len(best_output):
                best_output = output
    
        return best_output
    
    # Heuristic
    # The bigger the number the better. 8 is more compact than 2,2,2 etc...
    
    # Find the most factors you can have below or equal to y
    # output the number and unused factors that can be reinserted in this function
    def largestFactors(factors, y):
        assert(y > 1)
        # iterate from y to 2 and see if the factors are present.
        for i in xrange(y, 1, -1):
            try_another_number = False
            factors_below_y = getFactors(i)
            for number, copies in factors_below_y.iteritems():
                if number in factors:
                    if factors[number] < copies:
                        try_another_number = True
                        continue # not enough factors
                else:
                    try_another_number = True
                    continue # a factor is not present
    
            # Do we want to try another number, or was a solution found?
            if try_another_number == True:
                continue
            else:
                output = 1
                for number, copies in factors_below_y.items():
                    remaining = factors[number] - copies
                    if remaining > 0:
                        factors[number] = remaining
                    else:
                        del factors[number]
                    output *= number ** copies
    
                return (output, factors)
    
        return None # failed
    
    
    
    
    # Find prime factors. You can use any formula you want for this.
    # I am using elliptic curve factorization from http://sourceforge.net/projects/pyecm
    import pyecm, collections, copy
    
    getFactors_cache = {}
    def getFactors(n):
        assert(n != 0)
        # attempt to retrieve from cache. Returns a copy
        try:
            return copy.copy(getFactors_cache[n])
        except KeyError:
            pass
    
        output = collections.defaultdict(int)
        for factor in pyecm.factors(n, False, True, 10, 1):
            output[factor] += 1
    
        # cache result
        getFactors_cache[n] = output
    
        return copy.copy(output)
    
    import math
    
    def entropy():
        num = 2**32
        probability = 1./num
        return -(num) * probability * math.log(probability, 2)
        # the (num) * probability cancels out
    
    def longTo64(num):
        mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
        output = ""
    
        # special case for 0
        if num == 0:
            return mapping[0]
    
        while num != 0:
            output = mapping[num % 64] + output
            num /= 64
    
        return output
    
    def longTo85(num):
        mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!*'();:@&=+$,/?%#[]"
        output = ""
        base = len(mapping)
    
        # special case for 0
        if num == 0:
            return mapping[0]
    
        while num != 0:
            output = mapping[num % base] + output
            num /= base
    
        return output
    
    def stringToLong(string):
        mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~!*'();:@&=+$,/?%#[]"
        output = 0
        base = len(mapping)
    
        place = 0
        # check each digit from the lowest place
        for digit in reversed(string):
            # find the number the mapping of symbol to number, then multiply by base^place
            output += mapping.find(digit) * (base ** place)
            place += 1
    
        return output
    
    import base64
    import pickle
    
    # get some long list of numbers
    a = (854183415,1270335149,228790978,1610119503,1785730631,2084495271,
        1180819741,1200564070,1594464081,1312769708,491733762,243961400,
        655643948,1950847733,492757139,1373886707,336679529,591953597,
        2007045617,1653638786)
    
    # this gets you the url-safe string
    str64 = base64.urlsafe_b64encode(pickle.dumps(a,-1))
    print str64
    >>> gAIoSvfN6TJKrca3S0rCEqMNSk95-F9KRxZwakqn3z58Sh3hYUZKZiePR0pRlwlfSqxGP05KAkNPHUo4jooOSixVFCdK9ZJHdEqT4F4dSvPY41FKaVIRFEq9fkgjSvEVoXdKgoaQYnRxAC4=
    
    # this unwinds it
    a64 = pickle.loads(base64.urlsafe_b64decode(str64))
    print a64
    >>> (854183415, 1270335149, 228790978, 1610119503, 1785730631, 2084495271, 1180819741, 1200564070, 1594464081, 1312769708, 491733762, 243961400, 655643948, 1950847733, 492757139, 1373886707, 336679529, 591953597, 2007045617, 1653638786)
    
    10^9 (4 characters) = 1000000000 (10 characters)
    
    7829203478 = some random number...
    
    bool negative=(n<1)?true:false;
    int j=n%y;
    if(n==0 || n==1)
    {
    list.append(n);
    return;
    }
    while((long64)(n-j*y)>MAX_INT && y>1) //R has to be stored in int32
    {
    y--;
    j=n%y;
    }
    if(y<=1)
    fail //Number has no suitable candidate factors. This shouldn't happen
    
    int i=0;
    for(;i<j;i++)
    {
    list.append(y);
    }
    list.append(n-y*j);
    if(negative)
    list[0]*=-1;
    return;