幸运数问题

题目是:

定义“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888

定义“近似幸运号码”是能被任意一个幸运号码整除的那些号码,比如6,8,12,16

现在问对闭区间[a, b],“近似幸运号码”的个数。

 

解法:

算法的基本思路还是利用二叉树,先求出小于上限的所有幸运号码,然后求每个幸运号码的倍数,所有倍数在区间内的即为所求。
因为基本幸运号码为2个:6,8。设上限的数据位数为n,那么n位幸运号码的个数就是n个6或8的组合数:
S(n) = C(n,0) + C(n,1) + C(n,2) + ... + C(n,n),同理i位数的所有幸运号码个数为S(i)=C(i,0)+
C(i,1) + ... + C(i,i),i>=1。那么求从1位数到n位数的所有幸运号码时,可以利用二叉树来解决,
根节点为起始点,左走为6,右走为8,构建一个n+1层的满二叉树(根节点为第一层)。那么从第二层
到第n+1层的所有节点即为从1位数到n位数的所有幸运号码。根据二叉树的性质可知,n+1层满二叉树的
节点数总和为2^(n+1) - 1,除去根节点,所以从1位数到n位数的所有幸运号码个数为2^(n+1) - 2个。

(因为第i层的节点数位2^(i-1)个,所以从这里还可以得出一个数学公式,即:C(n,0) + C(n,1) + C(n,2) + ... + C(n,n) = 2^n)

我们构建满二叉树时,采用数组存储方式即可。如果所有2^(n+1) - 1个节点存入的话,则父子节点的
序号关系为第i个节点(i>0)的父节点为(i-1)/2,i节点的左子序号为2i+1,右子为2i+2。但是这里由于根节点
无意义,所以可以不存放,因此存放时,所有的节点序号就都减1,从而有第i个节点(i>2)的父节点为
(i-1-1)/2 = i/2-1。

在计算所有幸运号码的倍数时,如果在[a,b]内就将其放入结果集合中。在下面的代码中,结果集合使用的是stl的set容器,这样

可以避免有重复结果。当然结果也可以使用hash表等其他形式保存。

实现代码如下:

UINT GetDigitCount(UINT unInteger)  //求整数的位数
{
 UINT unCount = 0;
 while(unInteger > 0)
 {
  unCount++;
  unInteger /= 10;
 }
 return unCount;
}

 

 

typedef std::set CLLSet;

 

LONGLONG FindLuckyNumbers(UINT unLowerLimit,
        UINT unUpperLimit,
        UINT unBase1,
        UINT unBase2,
        CLLSet* pResultLNs)
{
 if(unLowerLimit > unUpperLimit || unBase1 > unBase2)
  return 0;

 UINT unUpperDigCnt = GetDigitCount(unUpperLimit); //上限的数据位数
 int nPureLNCount = pow(float(2), int(unUpperDigCnt + 1)) - 2;  //幸运号码
 LONGLONG* pllPureLNs = new LONGLONG[nPureLNCount];
 ZeroMemory(pllPureLNs, sizeof(LONGLONG)*nPureLNCount);
 pllPureLNs[0] = 6;
 pllPureLNs[1] = 8;
 for(int i=2; i {
  int nParent = i/2 - 1;
  pllPureLNs[i] = pllPureLNs[nParent]*10 + 6;
  pllPureLNs[++i] = pllPureLNs[nParent]*10 + 8;
 }
 pResultLNs->clear();
 LONGLONG llResultcount = 0;
 for(int i=0; i {
  UINT unMultiple = 1;
  LONGLONG llSemiLN = pllPureLNs[i];
  while(llSemiLN <= unUpperLimit)
  {
   if(llSemiLN >= unLowerLimit)
   {
    std::pair itRe = pResultLNs->insert(llSemiLN);
    if(itRe.second)
     llResultcount++;
   }
   llSemiLN = pllPureLNs[i] * (++unMultiple);
  }
 }
 delete [] pllPureLNs;
 return llResultcount;
}

 

 

int _tmain(int argc, _TCHAR* argv[])
{
 bool bContinue = true;
 while(bContinue)
 {
  UINT unBase1 = 6, unBase2 = 8;
  LONGLONG llLower = 0, llUpper = 0;
  LONGLONG llRe = 0;
  CLLSet setResults;
  fflush(stdout);
  printf("********************Lucky Number test program*********************/n");
  printf("1.Begin/r/n2.Exit/r/nYour select:");
  int nSel;
  scanf("%d", &nSel);
  switch(nSel)
  {
  case 1:
   printf("Lower limit:");
   scanf("%I64d", &llLower);
   printf("Upper limit:");
   scanf("%I64d", &llUpper);
   if(llLower > llUpper)
   {
    printf("Invalid range!/n");
    continue;
   }
   llRe = FindLuckyNumbers(llLower, llUpper, unBase1, unBase2, &setResults);
   if(llRe > 0)
   {
    printf("Lucky numbers between %I64d and %I64d are as follows:/n", llLower, llUpper);
    for(CLLSet::iterator it = setResults.begin();
     it != setResults.end(); it++)
    {
     printf("%I64d/n", *it);
    }
    printf("Result Count:%I64d/n", llRe);
   }
   break;
  case 2:
   bContinue = false;
   break;
  default:
   printf("Input error!/n");
   break;
  }
 }
 return 0;
}

你可能感兴趣的:(趣味题目)