题目来源于ACM竞赛。
要求,输入任意一个正整数,计算得到2^N%N,需要考虑溢出,并且有时间限制。
按照正常的循环求指数的运算,基本上在N比较大的时候一定会超时,因此为了实现这个要求只能寻求时间复杂度小于O(N)的算法。
相应的算法及测试代码如下:
对于两个算法中用long去申请局部变量的原因是为了防止溢出,尽管N是一个int变量,但是由于int集合在乘法运算中并不满足闭包性质,所以只有利用long才能解决问题。至于结果由于是已经%N,因此它一定小于N,仍然是一个int变量。要求,输入任意一个正整数,计算得到2^N%N,需要考虑溢出,并且有时间限制。
按照正常的循环求指数的运算,基本上在N比较大的时候一定会超时,因此为了实现这个要求只能寻求时间复杂度小于O(N)的算法。
相应的算法及测试代码如下:
1
class Program
2
{
3
static void Main(string[] args)
4
{
5
Console.WriteLine("请输入一个正整数:");
6
bool flag = false;
7
int test = 0;
8
while (!flag)
9
{
10
string s = Console.ReadLine();
11
flag = int.TryParse(s, out test);
12
flag = flag && (test > 0);
13
if (!flag)
14
Console.WriteLine("格式不正确,请重新输入:");
15
else
16
Console.WriteLine("您输入的正整数为:{0}", test);
17
}
18![]()
19
Stopwatch sw = new Stopwatch();
20
sw.Start();
21
int fast = computeFast(test);
22
sw.Stop();
23
Console.WriteLine("O(logN)计算结果为{0}", fast);
24
Console.WriteLine("O(logN)算法耗时{0}ms", sw.ElapsedMilliseconds);
25
sw.Reset();
26
sw.Start();
27
int slow = computeSlow(test);
28
sw.Stop();
29
Console.WriteLine("O(N)计算结果为{0}", slow);
30
Console.WriteLine("O(N)算法耗时{0}ms", sw.ElapsedMilliseconds);
31
Console.Read();
32
}
33![]()
34
static int computeFast(int n)
35
{
36
if (n <= 0)
37
throw new ArgumentException();
38
long result = 1;
39
long helper = 2;
40
int m = n;
41
while (m > 0)
42
{
43
if ((m & 1) == 1)
44
result = (result * helper) % n;
45
helper = ((helper % n) * (helper % n)) % n;
46
m = m >> 1;
47
}
48
return (int)result;
49
}
50![]()
51![]()
52
static int computeSlow(int n)
53
{
54
if (n <= 0)
55
throw new ArgumentException();
56
long result = 1;
57
for (int i = 0; i < n; i++)
58
{
59
result = (result << 1) % n;
60
}
61
return (int)result;
62
}
63
}

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

主要来说,这里面运用的数学定理不多,主要就是(a*b)%n=(a%n)*(b%n)%n。如果没有这个公式,可以说由于指数运算,long也必然无法满足要求而导致溢出。
至于第一种算法,主要就是将指数N分解成为二进制的形式,利用一个helper变量来维护当前需要乘的值。利用的是公式a^(m+n)=a^m*a^n。
经过测试,当N较大时,差距将比较明显——时间复杂度的区别还是非常值得注意的。
---------------------------------------------------------------
缥缈落花街 月圆月缺 望峦山平川 雁返君未还 怆然晚春残 忆天上人间
缥缈落花街 月圆月缺 望峦山平川 雁返君未还 怆然晚春残 忆天上人间