笔试题练习(五)

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

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

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
/**
*
*
@author phinecos
*
@since 2005-05-27
*/
public class test
{
private static Stringmultipy(Stringnum1,Stringnum2)
{
// 大数乘法
Stringresult = " 0 " ;
int i,j,n1,n2;
int len1 = num1.length();
int len2 = num2.length();
if (len1 < len2)
{
for (i = len1 - 1 ;i >= 0 ; -- i)
{
n1
= num1.charAt(i) - ' 0 ' ;
Stringsum
= " 0 " ;
for (j = 0 ;j < n1; ++ j)
{
sum
= add(sum,num2);
}
StringBuildertmpSB
= new StringBuilder(sum);
for (j = i;j < len1 - 1 ; ++ j)
{
tmpSB.append(
" 0 " );
}
result
= add(result,tmpSB.toString());
}
}
else
{
for (i = len2 - 1 ;i >= 0 ; -- i)
{
n2
= num2.charAt(i) - ' 0 ' ;
Stringsum
= " 0 " ;
for (j = 0 ;j < n2; ++ j)
{
sum
= add(sum,num1);
}
StringBuildertmpSB
= new StringBuilder(sum);
for (j = i;j < len2 - 1 ; ++ j)
{
tmpSB.append(
" 0 " );
}
result
= add(result,tmpSB.toString());
}
}

return result;
}
private static Stringadd(Stringnum1,Stringnum2)
{
Stringresult
= "" ;
int len1 = num1.length();
int len2 = num2.length();
int nAddOn = 0 ;
int i,j,n1,n2,sum;
StringBuildersb
= new StringBuilder();
for (i = len1 - 1 ,j = len2 - 1 ;i >= 0 && j >= 0 ; -- i, -- j)
{
n1
= num1.charAt(i) - ' 0 ' ;
n2
= num2.charAt(j) - ' 0 ' ;
sum
= n1 + n2 + nAddOn;

if (sum >= 10 )
{
nAddOn
= 1 ;
}
else
{
nAddOn
= 0 ;
}
sb.append(sum
% 10 );
}
if (len1 > len2)
{
for (;i >= 0 ; -- i)
{
n1
= num1.charAt(i) - ' 0 ' ;
sum
= n1 + nAddOn;
if (sum >= 10 )
{
nAddOn
= 1 ;
}
else
{
nAddOn
= 0 ;
}
sb.append(sum
% 10 );
}
}
else if (len2 > len1)
{
for (;j >= 0 ; -- j)
{
n2
= num2.charAt(j) - ' 0 ' ;
sum
= n2 + nAddOn;
if (sum >= 10 )
{
nAddOn
= 1 ;
}
else
{
nAddOn
= 0 ;
}
sb.append(sum
% 10 );
}
}

if (nAddOn > 0 )
{
sb.append(nAddOn);
}

sb.reverse();
result
= sb.toString();
return result;
}
private static Stringfactorial( int n)
{
Stringresult
= " 1 " ;
for ( int i = n;i >= 2 ; -- i)
{
result
= multipy(result,String.valueOf(i));
}
return result;
}
private static int countNFactZeroes( int n)
{
Stringresult
= factorial(n); // N!
System.out.println(result);
int count = 0 ;
for ( int i = result.length() - 1 ;i >= 0 ; -- i)
{
if (result.charAt(i) == ' 0 ' )
{
++ count;
}
else
break ;
}
return count;
}
public static void main(String[]args) throws Exception
{
System.out.println(countNFactZeroes(
18 ));
}
}

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

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> private static int countNFactZeroes2( int n)
{
int i,j,result = 0 ;
for (i = 5 ;i <= n;i += 5 ) // 循环次数为n/5
{ // 只针对可以整除5的分解因子
for (j = i;j % 5 == 0 ;j /= 5 ) // 此处的最大循环次数为LOG5(N)
{ // 当前分解因子可以整除几个5
++ result;
}
}
return result;
}

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

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> private static int countNFactZeroes3( int n)
{
int pow5,result = 0 ;
for (pow5 = 5 ;pow5 <= n;pow5 *= 5 ) // 此处的循环次数为LOG5(N)
{
result
+= n / pow5;
}
return result;
}

设最大数为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,即相加,便得到以下算法

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> private static int countNFactZeroes4( int n)
{
int result = 0 ;
int m = n / 5 ;
while (m > 0 )
{
result
+= m;
m
= m / 5 ;
}
return result;
}

等比数列的项数为

log5(N) , 即为循环的次数 , 故复杂度为 log5(N)

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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> /* ********************************************************************** */
/* Author:phinecosDate:2009-05-27 */
/* ********************************************************************** */
#include
< iostream >
#include
< cassert >
using namespace std;

int StringToInt( const char * str)
{
// 考虑八进制,十六进制,十进制
assert(str != NULL);
assert(strlen(str)
!= 0 );

int result = 0 ;
int sign = 1 ; // 符号位
int radix = 10 ; // 默认是进制
const char * p = str;
if ( * p == ' - ' )
{
// 负数
sign = - 1 ;
++ p;
}
if ( * p == ' 0 ' )
{
// 以'0'开头,或者是八进制,或者是十六进制
if (( * (p + 1 ) == ' x ' ) || ( * (p + 1 ) == ' X ' ))
{
// 16进制
radix = 16 ;
p
+= 2 ; // 跳过'0x'
}
else
{
// 八进制
radix = 8 ;
++ p; // 跳过'0'
}
}
while ( * p != ' /0 ' )
{
if (radix == 16 )
{
// 16进制
if ( * p >= ' 0 ' && * p <= ' 9 ' )
{
result
= result * radix + * p - ' 0 ' ;
}
else
{
// 字母
int tmp = toupper( * p); // 大写化
result = result * radix + tmp - ' A ' + 10 ;
}
}
else
{
// 8或进制,不含字母
result = result * radix + * p - ' 0 ' ;
}
++ p;
}
return result * sign;
}
int main()
{
cout
<< StringToInt( " -355643 " ) << endl;
cout
<< StringToInt( " -0x200 " ) << endl;
cout
<< StringToInt( " -0123 " ) << endl;
cout
<< StringToInt( " -0x7FFFFFFF " ) << endl;
return 0 ;
}

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

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> /* ********************************************************************** */
/* Author:phinecosDate:2009-05-27 */
/* ********************************************************************** */
#include
< iostream >
using namespace std;

bool isExist[ 256 ] = { false }; // 256个字符是否存在的标志

char * merge( char a[], int n, char b[], int m)
{
char * c = new char [m + n];
int i,k = 0 ;
// 判断数组a中哪些字符存在
for (i = 0 ;i < n; ++ i)
{
isExist[a[i]]
= true ;
}
// 判断数组b中哪些字符存在
for (i = 0 ;i < m; ++ i)
{
if (isExist[b[i]] == true )
{
isExist[b[i]]
= false ;
}
}
// a中存在,b中不存在的加入新数组
char ch;
for (i = 0 ;i < 256 ; ++ i)
{
if (isExist[i] == true )
{
ch
= ( char )i;
c[k
++ ] = ch;
}
}
c[k]
= ' /0 ' ;
return c;

}
int main()
{
char a[] = { ' a ' , ' c ' , ' 4 ' , ' s ' , ' v ' , ' y ' , ' Y ' , ' C ' , ' E ' };
char b[] = { ' c ' , ' y ' , ' , ' , ' u ' , ' r ' };
int n = sizeof (a) / sizeof ( char );
int m = sizeof (b) / sizeof ( char );
char * c = merge(a,n,b,m);
cout
<< c << endl;
delete[]c;
return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值