快速判断一个非负整数是否为完全平方数
来源:互联网 发布:node readline 编辑:程序博客网 时间:2024/06/05 03:58
定义:
若一个数能表示成某个自然数的平方的形式,则称这个数为完全平方数。性质:
1. 完全平方数是非负整数。
2. 十进制的完全平方数的末位数只能是0, 1, 4, 5, 6, 9; 十六进制的完全平方数的末位数只能是0, 1, 4, 9。
3. 除0以外的完全平方数是从1开始的连续的奇数的和,例如: 1 = 1, 4 = 1 + 3, 9 = 1 + 3 + 5, 16 = 1 + 3 + 5 + 7。
判断思路:
1. 利用定义,即对输入的非负整数开根,得到浮点数,再四舍五入到整数(即最接近的整数),看该整数的平方是否与输入的非负整数相同。
2. 利用性质3,首先判断输入的非负整数是否为0,再判断是否为从1开始的连续的奇数的和(即依次减去1, 3, 5...,直到出现等于0或小于0的结果,等于0则是完全平方数,小于0则不是)
优化思路:
利用性质2,通过输入的非负整数的末尾数字来过滤不可能是完全平方数的数。在十进制表示下,完全平方数的末位数只能是0, 1, 4, 5, 6, 9,这是比较好理解的(即枚举1到9的平方的末尾数)。同理,在十六进制表示下,我们只需要枚举1到15的平方的末尾数即可,为0,1,4,9,如下所示。
0x0 * 0x0 % 0x10 = 0x0
0x1 * 0x1 % 0x10 = 0x1
0x2 * 0x2 % 0x10 = 0x4
0x3 * 0x3 % 0x10 = 0x9
0x4 * 0x4 % 0x10 = 0x0
0x5 * 0x5 % 0x10 = 0x9
0x6 * 0x6 % 0x10 = 0x4
0x7 * 0x7 % 0x10 = 0x1
0x8 * 0x8 % 0x10 = 0x0
0x9 * 0x9 % 0x10 = 0x1
0xa * 0xa % 0x10 = 0x4
0xb * 0xb % 0x10 = 0x9
0xc * 0xc % 0x10 = 0x0
0xd * 0xd % 0x10 = 0x9
0xe * 0xe % 0x10 = 0x4
0xf * 0xf % 0x10 = 0x1
这里有人会问了,为什么取十六进制表示下的末尾数呢?这里我做如下解释:1. 我们都知道,计算机以二进制来表示数字,位运算速度是最快的,十六进制表示下的末尾数就是二进制下的末4位数,只需要将输入的非负整数与0xF做按位与(&)运算,就可以得到十六进制下的末尾数。因而,得到十六进制下的末尾数比得到十进制下的末尾数要快。
2. 此外,十进制末尾数的过滤比例为1-(5/10)=1/2;十六进制末尾数的过滤比例则为1-(4/16)=3/4;十六进制比十进制能够过滤掉更多的数。
3. 再多说一句,取2^n进制(比如八进制、六十四进制)都是可以的,n越大,过滤掉的数的比例就越高。
代码:
import math, timeitimport matplotlib.pyplot as pltimport numpy as npdef is_perfect_square_sqrt(n): root = int(math.sqrt(n) + 0.5) return root ** 2 == n# Filter hexadecimal number whose last digit in not in [0, 1, 4, 9]def hex_filter(n): digit = n & 0xf if digit not in [0, 1, 4, 9]: return False else: return Truedef show_last_digit(): print 'If a number is a perfect square, \ then the last digit of the number in hexadecimal notation must be 0, 1, 4 or 9.' for i in range(16): print "%s * %s %% %s = %s" % (hex(i), hex(i), hex(16), hex((i ** 2) % 16))# All perfect squares are sums of consecutive odd numbers:# 1 = 1# 4 = 1 + 3# 9 = 1 + 3 + 5# 16 = 1 + 3 + 5 + 7def is_perfect_square_sub(n): i = 1; while True: if n < 0: return False elif n == 0: return True else: n -= i i += 2if __name__ == '__main__': # Show the possible last digit of the hexadecimal perfect square number # show_last_digit() # Check if the results of the four methods are the same ''' sqrt = [] sqrt_filter = [] sub = [] sub_filter = [] for i in range(100000): if is_perfect_square_sqrt(i): sqrt.append(i) if is_perfect_square_sub(i): sub.append(i) if hex_filter(i) and is_perfect_square_sqrt(i): sqrt_filter.append(i) if hex_filter(i) and is_perfect_square_sub(i): sub_filter.append(i) print sqrt == sqrt_filter print sub == sub_filter print sqrt == sub print sqrt_filter == sub_filter print sqrt ''' t = [] t.append(timeit.timeit(stmt="for i in range(100000): is_perfect_square_sqrt(i)", setup="from __main__ import is_perfect_square_sqrt", number=1000)) t.append(timeit.timeit(stmt="for i in range(100000): is_perfect_square_sub(i)", setup="from __main__ import is_perfect_square_sub", number=1000)) t.append(timeit.timeit(stmt="for i in range(100000): hex_filter(i) and is_perfect_square_sqrt(i)", setup="from __main__ import is_perfect_square_sqrt, hex_filter", number=1000)) t.append(timeit.timeit(stmt="for i in range(100000): hex_filter(i) and is_perfect_square_sub(i)", setup="from __main__ import is_perfect_square_sub, hex_filter", number=1000)) dic = dict(zip(['sqrt', 'sub', 'sqrt_filter', 'sub_filter'], t)) #print dic for i, key in enumerate(dic): plt.bar(i, dic[key]) # i indicates the i-th bar plt.xticks(np.arange(len(dic)) + 0.4, dic.keys()) plt.yticks(dic.values()) plt.xlabel('Method') plt.ylabel('Running time') plt.show()
运行时间比较:
我们通过循环1000次,每次循环判断从0到99999每个数是否为完全平方数,来比较代码中4种算法的性能。运行时间见下图:
由于sqrt_filter和sqrt运行时间较接近,所以y轴的运行时间重叠看不清,分别是33.23355389和41.42628694。
从结果来看,hex_filter优化的时间并没有我想的那么多,可能是因为将hex_filter写作函数,函数调用增加了些额外的时间。
0 0
- 快速判断一个非负整数是否为完全平方数
- 怎么判断一个数是否为完全平方数
- 判断一个数是否为完全平方数
- 判断是否为完全平方数
- 判断一个整数是否平方数
- 判断一个数是否为平方数
- 判断一个数是否为平方数
- 367. Valid Perfect Square--判断一个数是否为完全平方数
- 判断一个非负整数是否为2的n次幂?-by大彬
- 如何判断一个数是否是完全平方数
- 判断一个数是否是完全平方数
- 如何判断一个整数是不是完全平方数
- 判断某整数是否为两数平方之和
- 判断是否为平方数
- 判断一个整数是否为回文数
- 判断一个整数是否为回文数
- C++判断一个数是否为整数
- 判断一个整数是否为回文数
- 插入排序(个人理解)
- 如何在技术面试中脱颖而出(上)
- 签名文件查询
- codecomb 2093【牛宫】
- nyoj-238-小明的调查统计
- 快速判断一个非负整数是否为完全平方数
- 【Python】多线程下载韩寒博客文章
- 虚拟机三种网络模式该如何上网指导
- 毕业之后-初入职
- 使用临时变量提高Java代码性能 (转)
- 黑马程序员-@property与@synthesize的用法
- spring、ibatis 整合
- 【算法】统计qq一天中每秒在线人数
- Redis如何处理客户端连接