1, 对任意输入的正整数N,编写程序求N!的尾部连续0的个数,并指出计算复杂度。如:18!=6402373705728000,尾部连续0的个数是3。(不用考虑数值超出计算机整数界限的问题)

解法1:(直接大数计算N!

  1. /**  
  2.  *   
  3.  * @author phinecos  
  4.  * @since 2005-05-27  
  5.  */ 
  6. public class test   
  7. {  
  8.     private static String multipy(String num1, String num2)  
  9.     {//大数乘法  
  10.         String result = "0";  
  11.         int i,j,n1,n2;  
  12.         int len1 = num1.length();  
  13.         int len2 = num2.length();  
  14.         if (len1 < len2)  
  15.         {  
  16.             for (i = len1 -1; i >=0; --i)  
  17.             {  
  18.                 n1 = num1.charAt(i) - '0';  
  19.                 String sum = "0";  
  20.                 for (j = 0; j < n1; ++j)  
  21.                 {  
  22.                     sum = add(sum,num2);  
  23.                 }  
  24.                 StringBuilder tmpSB = new StringBuilder(sum);  
  25.                 for (j = i; j < len1 -1; ++j)  
  26.                 {  
  27.                     tmpSB.append("0");  
  28.                 }  
  29.                 result = add(result,tmpSB.toString());  
  30.             }  
  31.         }  
  32.         else 
  33.         {  
  34.             for (i = len2 -1; i >=0; --i)  
  35.             {  
  36.                 n2 = num2.charAt(i) - '0';  
  37.                 String sum = "0";  
  38.                 for (j = 0; j < n2; ++j)  
  39.                 {  
  40.                     sum = add(sum,num1);  
  41.                 }  
  42.                 StringBuilder tmpSB = new StringBuilder(sum);  
  43.                 for (j = i; j < len2 -1; ++j)  
  44.                 {  
  45.                     tmpSB.append("0");  
  46.                 }  
  47.                 result = add(result,tmpSB.toString());  
  48.             }  
  49.         }  
  50.  
  51.         return result;  
  52.     }      
  53.     private static String add(String num1, String num2)  
  54.     {  
  55.         String result = "";  
  56.         int len1 = num1.length();  
  57.         int len2 = num2.length();  
  58.         int nAddOn = 0;  
  59.         int i,j,n1,n2,sum;  
  60.         StringBuilder sb = new StringBuilder();  
  61.         for (i = len1 - 1,j = len2 - 1 ; i >= 0 && j >= 0; --i,--j)  
  62.         {  
  63.             n1 = num1.charAt(i) - '0';  
  64.             n2 = num2.charAt(j) - '0';  
  65.             sum = n1 + n2 + nAddOn;  
  66.               
  67.             if (sum >= 10)  
  68.             {  
  69.                 nAddOn = 1;  
  70.             }  
  71.             else 
  72.             {  
  73.                 nAddOn = 0;  
  74.             }  
  75.             sb.append(sum % 10);  
  76.         }  
  77.         if (len1 > len2)  
  78.         {  
  79.             for (; i >= 0; --i)  
  80.             {  
  81.                 n1 = num1.charAt(i) - '0';  
  82.                 sum = n1 + nAddOn;  
  83.                 if (sum >= 10)  
  84.                 {  
  85.                     nAddOn = 1;  
  86.                 }  
  87.                 else 
  88.                 {  
  89.                     nAddOn = 0;  
  90.                 }  
  91.                 sb.append(sum % 10);  
  92.             }  
  93.         }  
  94.         else if (len2 > len1)  
  95.         {  
  96.             for (; j >= 0; --j)  
  97.             {  
  98.                 n2 = num2.charAt(j) - '0';  
  99.                 sum = n2 + nAddOn;  
  100.                 if (sum >= 10)  
  101.                 {  
  102.                     nAddOn = 1;  
  103.                 }  
  104.                 else 
  105.                 {  
  106.                     nAddOn = 0;  
  107.                 }  
  108.                 sb.append(sum % 10);  
  109.             }  
  110.         }  
  111.           
  112.         if (nAddOn > 0)  
  113.         {  
  114.             sb.append(nAddOn);  
  115.         }  
  116.           
  117.         sb.reverse();  
  118.         result = sb.toString();  
  119.         return result;  
  120.     }  
  121.     private static String factorial(int n)  
  122.     {  
  123.         String result = "1";  
  124.         for (int i = n; i >= 2; --i)  
  125.         {  
  126.             result = multipy(result,String.valueOf(i));  
  127.         }  
  128.         return result;  
  129.     }  
  130.     private static int countNFactZeroes(int n)  
  131.     {  
  132.         String result = factorial(n);//N!  
  133.         System.out.println(result);  
  134.         int count = 0;  
  135.         for (int i = result.length()-1; i >= 0; --i)  
  136.         {  
  137.             if (result.charAt(i) == '0')  
  138.             {  
  139.                 ++count;  
  140.             }  
  141.             else 
  142.                 break;  
  143.         }  
  144.         return count;  
  145.     }  
  146.     public static void main(String[] args) throws Exception  
  147.     {  
  148.         System.out.println(countNFactZeroes(18));  
  149.     }  

解法2连续K0,则说明是10^K的倍数,即(2×5)^ K= 2^K× 5^K;待求的数为N*(N-1)(N-2)………1,由于每两个数至少可以分解出122肯定比5多,因此K的个数取决于上式的分解因子中有几个5的问题;能拆解出5的只可能是5的倍数,而能拆解出多少个5则看这个数是5的几次方的倍数了。时间复杂度是Onlogn

  1. private static int countNFactZeroes2(int n)   
  2. {  
  3.     int i,j,result=0;  
  4.     for(i = 5; i <= n; i += 5) // 循环次数为n/5  
  5.     {//只针对可以整除5的分解因子  
  6.         for(j = i; j%5 == 0; j /= 5) // 此处的最大循环次数为 LOG5(N)  
  7.         {//当前分解因子可以整除几个5  
  8.             ++result;  
  9.         }   
  10.     }   
  11.     return result;   

解法3N不变,pow55的幂递增,此算法的思想是求出N以内所有被5整除的数的个数,所有被25整除的个数(在5的基础上多出了一个5因子),所有被125整除的个数(在25的基础上多出了一个5因子)。。。

  1. private static int countNFactZeroes3(int n)   
  2.  {  
  3.      int pow5,result=0;   
  4.      for(pow5 = 5; pow5 <= n; pow5 *= 5) // 此处的循环次数为LOG5(N)  
  5.      {  
  6.          result += n / pow5;   
  7.      }   
  8.      return result;   
  9.  } 

设最大数为N, 5^(n+1)  > N  >= 5^n
[N/5] + [N/(5^2)] + [N/(5^3)] + ... + [N/(5^n)]
即为连续0的个数

上述式子的项数为log5(N),即为循环的次数,故复杂度为log5(N)
解法4:由解法3可得如下:

[N/5] + [N/(5^2)] + [N/(5^3)] + ... + [N/(5^n)]

=[N/5] + [[N/5]/5] + [ [[N/5]/5]/5] + ... + [。。。]

=A1+ [A1/5] + [A2/5] + ... + [An-1/5]

即上述各项构成等比数列An=An-1/5等比为1/5

即对A1反复除5只要其大于0即相加便得到以下算法

  1. private static int countNFactZeroes4(int n)   
  2.    {  
  3.        int result=0;   
  4.        int m = n/5;  
  5.        while (m > 0)  
  6.        {  
  7.            result += m;  
  8.            m = m/5;  
  9.        }  
  10.        return result;   
  11.        } 

等比数列的项数为log5(N)即为循环的次数故复杂度为log5(N)

 

 

 

2,题目: 请编写一个 C 函数,该函数将给定的一个字符串转换成整数

  1. /************************************************************************/ 
  2. /* Author: phinecos Date:2009-05-27                                                                     */ 
  3. /************************************************************************/ 
  4. #include <iostream>  
  5. #include <cassert>  
  6. using namespace std;  
  7.  
  8. int StringToInt(const char* str)  
  9. {//考虑八进制,十六进制,十进制  
  10.     assert(str != NULL);  
  11.     assert(strlen(str) != 0);  
  12.  
  13.     int result = 0;  
  14.     int sign = 1;//符号位  
  15.     int radix = 10;//默认是进制  
  16.     const char *p = str;  
  17.     if (*p == '-')  
  18.     {//负数  
  19.         sign = -1;  
  20.         ++p;  
  21.     }  
  22.     if (*p == '0')  
  23.     {//以'0'开头,或者是八进制,或者是十六进制  
  24.         if ((*(p+1) == 'x') || (*(p+1) == 'X'))  
  25.         {//16进制  
  26.             radix = 16;  
  27.             p += 2;//跳过'0x'  
  28.         }  
  29.         else 
  30.         {//八进制  
  31.             radix = 8;  
  32.             ++p;//跳过'0'  
  33.         }  
  34.     }  
  35.     while (*p != '\0')  
  36.     {  
  37.         if (radix == 16)  
  38.         {//16进制  
  39.             if (*p >='0' && *p <= '9')  
  40.             {  
  41.                 result = result*radix + *p - '0';  
  42.             }  
  43.             else 
  44.             {//字母  
  45.                 int tmp = toupper(*p);//大写化  
  46.                 result = result*radix + tmp -'A'+10;  
  47.             }  
  48.         }  
  49.         else 
  50.         {//8或进制,不含字母  
  51.             result = result*radix + *p - '0';  
  52.         }  
  53.         ++p;  
  54.     }  
  55.     return result * sign;  
  56. }  
  57. int main()  
  58. {  
  59.     cout << StringToInt("-355643") << endl;  
  60.     cout << StringToInt("-0x200") << endl;  
  61.     cout << StringToInt("-0123") << endl;  
  62.     cout << StringToInt("-0x7FFFFFFF") << endl;  
  63.     return 0;  

3,已知两个字符数组,char a[m],b[n],m>n>1000,写程序将a中存在,但b中不存在的元素放入字符数组c中,并说明算法的时间复杂度

  1. /************************************************************************/ 
  2. /* Author: phinecos Date:2009-05-27                                                                     */ 
  3. /************************************************************************/ 
  4. #include <iostream>  
  5. using namespace std;  
  6.  
  7. bool isExist[256] = {false};//256个字符是否存在的标志  
  8.  
  9. char* merge(char a[], int n, char b[],int m)  
  10. {  
  11.     char *c = new char[m+n];  
  12.     int i,k = 0;  
  13.     //判断数组a中哪些字符存在  
  14.     for (i = 0; i < n; ++i)  
  15.     {  
  16.         isExist[a[i]] = true;  
  17.     }  
  18.     //判断数组b中哪些字符存在  
  19.     for (i = 0; i < m; ++i)  
  20.     {  
  21.         if (isExist[b[i]] == true)  
  22.         {  
  23.             isExist[b[i]] = false;  
  24.         }  
  25.     }  
  26.     //a中存在,b中不存在的加入新数组  
  27.     char ch;   
  28.     for (i = 0; i < 256; ++i)  
  29.     {  
  30.         if (isExist[i] == true)  
  31.         {  
  32.             ch = (char)i;  
  33.             c[k++] = ch;  
  34.         }  
  35.     }  
  36.     c[k] = '\0';  
  37.     return c;  
  38.  
  39. }  
  40. int main()  
  41. {  
  42.     char a[] = {'a','c','4','s','v','y','Y','C','E'};  
  43.     char b[] = {'c','y',',','u','r'};  
  44.     int n = sizeof(a) / sizeof(char);  
  45.     int m = sizeof(b) / sizeof(char);  
  46.     char *c = merge(a,n,b,m);  
  47.     cout << c << endl;  
  48.     delete [] c;  
  49.     return 0;