趣味算法:返回完全幂的绝对差

BingWay原创作品,转载请注明作者和出处。

之前写过一篇趣味算法,返回不重复数,引得园子里很多算法高手技痒,我看到的关于返回不重复数的文章有好几篇。这使我更坚信,园子是个很好的技术交流平台。前两天又写了一道算法,原题是英文的,本人英文不是太好,初步翻译了一下,效果自认为还过得去,但怕翻译出来误导了大家,特请坤坤和他那边的英语牛人帮忙翻译,在此,我要特别感谢他们。好了,废话少说,上题目:
原:
A number is called a perfect power if it can be written in the form m^k, where m and k are positive integers, and k > 1. Given two positive integers A and B, find the two perfect powers between A and B, inclusive, that are closest to each other, and return the absolute difference between them. If less than two perfect powers exist in the interval, return -1 instead.
A will be between 1 and 10^18, inclusive.B will be between A+1 and 10^18, inclusive.

译:
如果一个数是以m^k这种格式,当m和k都是正整数,而且k大于1,这个数就可以被称为完全幂。给出两个正整数A和B,发现两个完全幂包含在A和B之间,而且这两个数字最接近。并返回一个他们之间的绝对差。如果在区间内存在的完全幂小于两个,就返回-1.
A的范围是1至10^18,B的范围是A+1至10^18。

测试数据:
1,4                           Returns: 3
8,9                           Returns: 1(1是完全幂)
10,15                      Returns: -1
1,1000000000000000000         Returns: 1 (最大测试范围)
80000,90000                   Returns: 80
测试数据及返回结果有一定的规律,看看哪位能找出运算规律。
我的算法:
ContractedBlock.gif ExpandedBlockStart.gif 算法
        static long INF = 2000000000000000000;
        
static long nearestCouple(long A, long B)
        {
            
long res = INF;
            List
<long> all = new List<long>();
            if(B == A + 1)
            {
                 return  res=1;
            }
            
for (int k = 2; ; ++k)
            {
                
long left = Math.Abs(root(A, k)); //返回绝对值
                long right = Math.Abs(root(B + 1, k)) - 1;
                
if (right < 2)
                    
break;
                
if (k == 2)
                {
                    
if (left < right)
                    {
                        res 
= Math.Min(res, 2 * left + 1);
                    }
                    
continue;
                }
                
for (long x = left; x <= right; ++x)
                {
                    
long v = pow(x, k);
                    
if (v < A || v > B)
                        
throw new Exception();
                    all.Add(v);
                    
long u = Math.Abs(root(v, 2));
                    
long u2 = pow(u, 2);
                    
long uu2 = pow(Math.Max(1, u - 1), 2);
                    
long uuu2 = pow(u + 12);
                    
if (u2 > A && u2 < B && u2 != v)
                        res 
= Math.Min(res, Math.Abs(u2 - v));
                    
if (uu2 > A && uu2 < B && uu2 != v)
                        res 
= Math.Min(res, Math.Abs(uu2 - v));
                    
if (uuu2 > A && uuu2 < B && uuu2 != v)
                        res 
= Math.Min(res, Math.Abs(uuu2 - v));
                }
            }
            all.Sort();
            
for (int i = 0; i < all.Count - 1++i)
                
if (all[i] != all[i + 1])
                    res 
= Math.Min(res, Math.Abs(all[i] - all[i + 1]));//得到绝对差
            return res == INF ? -1 : res;//判断是否小于完全幂,小于完全幂返回-1,否则返回res
        }
        
static long root(long n, long p)
        {
            
long z = Math.Max(1, (long)Math.Pow(n, 1.0 / p) - 2);//比较返回较大的数
            while (pow(z, p) < n)//z的p次幂是否小于n
            {
                
++z;
            }
            
if (pow(z, p) > n)
            {
                
return -z;
            }
            
else
                
return z;

        }
        
static long pow(long a, long k)
        {
            
if (k == 0)
            {
                 
return 1;
            }
            
else if (k % 2 == 0)
            {
                
long z = pow(a, k / 2);
                
return mul(z, z);
            }
            
else
            {
                
return mul(a, pow(a, k - 1));
            }

        }
        
static long mul(long a, long b)
        {
            
if (INF / a < b)
                
return INF;
            
else
                
return a * b;
         }

转载于:https://www.cnblogs.com/lovexyz123/archive/2009/09/14/1566283.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值