PythonTip--8.2

来源:互联网 发布:mac照片是什么意思啊 编辑:程序博客网 时间:2024/06/05 09:08

大幂次运算

题目描述:
给你两个正整数a(0 < a < 100000)和n(0 <= n <=100000000000),计算(a^n) %
20132013并输出结果

思路:
第一个就是直接使用Python内置库里面的pow()函数,专门就是用来处理这个问题的。
第二个就是使用了一个公式:
这里写图片描述
将幂次分为两种情况,若为偶数则可以将幂次提取一个2出来,放入数a中,这样就可以减小幂次。如果是奇数的话,就先提一个a出来这样b就是偶数了,再执行同样的操作。

至于减小幂次是否能够简化运算,可以找一个例子:
2^31若正常运算需要执行30次2的相乘。
使用第二种方法:2^15*2^16
==> 2^7*2^8*2^8*2^8
==> 2^3*2^4*2^4*2^4*2^4*2^4*2^4*2^4*
==>…….
很明显,这样算的话,有很多运算是重复的,可以简化操作。
于是下面贴代码:

a=85265n=10000256625323from time import clockdef func(a,n):    return pow(a,n,20132013)begin = clock()print(func(a,n))finish = clock()print(finish-begin)# 优化后的代码def func2(a,n):    ans = 1    while n:        if n%2 ==1:            ans = (ans * a)%20132013        n //=2        a = a*a%20132013    return ansbegin = clock()print(func2(a,n))finish = clock()print(finish-begin)

使用了python的time.clock()函数来计算时间:

6434294
2.8049393797291378e-05
6434294
1.9358032338975736e-05

计算结果都是一样的,可是时间相差了将近1/3。

============分割线============

密码生成

题目描述: 生活在当代社会,我们要记住很多密码,银行卡,qq,人人,微博,邮箱等等。小P经过一番思索之后,发明了下面这种生成密码方法:
给定两个正整数a和b, 利用a / b我们会到的一个长度无限的小数(若a / b不是无限小数,
比如1/2=0.5,我们认为0.5是0.5000000…,同样将其看做无限长的小数),小P将该小数点后第x位到第y位的数字
当做密码,这样,无论密码有多长,小P只要记住a,b,x,y四个数字就可以了,牢记密码再也不是那么困难的事情了。 现在告诉你a,b,x,y(0
< a,b <= 20132013, 0 < x <= y < 100000000000),请你输出密码。 例如:a = 1, b = 2,
x = 1, y = 4, 则 a / b = 0.5000000…, 输出小数点后第1到4位数字,即5000

思路:
这道题用了模拟除法运算,具体的运算在代码中有备注。

代码:

a,b,x,y = 1,3,1,4def func(a,b,x,y):    '''模拟除法'''    # 使a<b    a = a%b    # 最后输出    result = ''    # 除的过程中若有重复的就可以直接取结果    history = {}    size = y    while len(result) < y:        # 若被除数为0,则所有的商都为0,所以要在后面补0        if a == 0:            result = result + '0'*(size-len(result))            break        # 若被除数已经被除过了,说明经过中间那么多次的运算又重复了,则可以直接取商        if a in history:            # 字典中的值是被除数取商的第一个位置            remain = result[history[a]:]            # 只要位数不够,都可以直接补            while len(result)<y:                result+=remain            # 去除位数多的            result=result[:y]            break        #  将当前被除数加入字典,值为商在result的索引        history[a]=len(result)        a*=10        while a<b:            #乘一次10,补一个0            a*=10            result +='0'        #  商        temp = a//b        result+=str(temp)        # 取余,循环        a %=b    return result[x-1:y]print(func(a,b,x,y))

============分割线============

最大连续子序列

题目描述:
给你一个整数list L, 如 L=[2,-3,3,50], 求L的一个连续子序列,使其和最大,输出最大子序列的和。

思路:
方法1:最简单了,就是遍历所有序列中的所有可能,然后找到最大的一个。
代码也就一行就可以搞定。使用了三重循环,两个for循环在外层,然后里面又用了一个sum,最后使用max找出最大的。

代码1:

def func1(L):    return max([sum(L[i:j]) for i in range(len(L)) for j in range(len(L)+1) if i<j])

方法2: 这就比上面的方法要好一点了。只需要2层循环,第一层for循环遍历开始位置,第二层是用来求和,只要当前的和大于最大和时就进行替换。

代码2:

def func2(L):    max_ = 0    for i in range(len(L)):        sum_ = 0        for j in range(i,len(L)):            sum_+=L[j]            if max_<sum_:                max_ = sum_    return max_

方法3: 这个应该是最优的了。只用了一层循环,因为在序列中,若开始元素是负数,那么这个负数肯定不会是最大子序列的开始,和加上负数只会变小,那还不如不加这个负数大呢。所以只要拓展下,序列开始的一段和如果是负数,那么肯定不会是最大子序列。因此如果小于0就可以去掉,重新计数。

代码3:

def func3(L):    max_ = 0    sum_ = 0    for i in range(len(L)):        sum_+=L[i]        if sum_>max_:            max_ = sum_        elif sum_<0:            sum_ = 0    return max_

同样用time.clock()进行计时,序列使用L=[2,-3,3,50,23,-5,4]

76
func1: 4.622224048286044e-05
76
func2: 1.5407413494286808e-05
76
func3: 7.111113920440064e-06

很明显,func3是用时最短的,如果序列长一点的话应该差异会更明显。

原创粉丝点击