【python算法手册】解决数学问题

1.1一段神奇的字符

一段神奇的字符也称为巧填数据问题,是算法中的经典问题,也是谷歌公司推出的一道面试题。在实际应用中我们通常采用穷举法解决这个问题。

1.1.1问题描述

字母代表0-9的数字中的一个,且不重复。在下面公式中,首位不能是0。

he + she = you

计算出各个字母代表的数字,来表示上面公式。

1.1.2具体实现
from datetime import datetime

class data_struct(object):
    def __init__(self,letter,status):
        self.letter = letter
        self.status = status
        if self.status == True:
            self.dight = [0,1,2,3,4,5,6,7,8,9]
        else:
            self.dight = [1,2,3,4,5,6,7,8,9]

    @staticmethod
    def norepet(list0):
        length = len(list0)
        list1 = [0 for i in range(10)]
        for i in range(length):
            list1[list0[i]]+=1
            if list1[list0[i]]>1:
                return False
        return True

if __name__ == '__main__':
    """he + she = you"""
    letterh = data_struct('h',True).dight
    lettere = data_struct('e',False).dight
    letters = data_struct('s',True).dight
    lettery = data_struct('y',True).dight
    lettero = data_struct('o',False).dight
    letteru = data_struct('u',False).dight
    start_time = datetime.now()
    for h in letterh:
        for e in lettere:
            for s in letters:
                for y in lettery:
                    for o in lettero:
                        for u in letteru:
                            list0 = [h,e,s,y,o,u]
                            if True == data_struct.norepet(list0):
                                str1 = str(h) + str(e)
                                str2 = str(s) + str(h) + str(e)
                                str3 = str(y) + str(o) + str(u)
                                if int(str1)+int(str2)==int(str3):
                                    print(str1,str2,str3)
    end_time = datetime.now()
    diff_time = end_time-start_time
    print(diff_time)
1.1.3输出结果

在这里插入图片描述

1.2 1000以内的完全数

完全数是一些特殊的自然数,满足所有的真因数(除自身以外)的和等于它本身这一条件

1.2.1问题描述

第一个完全数是6=1+2+3
第二个完全数是28=1+2+4+7+14
第三个是496=1+2+4+8+16+31+62+124+8128

1.2.2 算法分析

完全数有许多性质:

  • 可以写成连续自然数的和
  • 全部因数导数的和都是2
    • 1/1+1/2+1/3+1/6=2
    • 1/1+1/2+1/4+1/7+1/14+1/28=2
  • 除6以外的完全数,可以写成连续奇立方数之和
    • 28=13+33
    • 496=13+33+53+73
1.2.3代码实现
def approximateNumber(num:int):
    res = []
    for divsors in range(1,num):
        # 找出这个数中所有除自身外的约数
        temp = []
        for divsor in range(1,divsors,1):
            if divsors%divsor==0:
                temp.append(divsor)
        tempSum = sum(temp)
        if tempSum==divsors:
            res.append(divsors)
    return res

print(approximateNumber(1000))
1.2.4输出结果

在这里插入图片描述

1.3 多进程验证歌德巴赫猜想

1.3.1 问题描述

是不是所有的大于2的偶数,都可以表示为两个素数的呢? 这个问题是德国数学家哥德巴赫(C.Goldbach,1690-1764)于1742年6月7日在给大数学家欧拉的信中提出的,所以被称作哥德巴赫猜想。在现实应用中,通常采用枚举法解决该问题。

1.3.2 算法分析:枚举法

可以把问题归纳为在指定范围内(1~2000)验证其中每一个偶数是否满足哥德巴赫猜想,如果有一个数不满足的话,就跳出循环,否定该猜想。
上述问题的核心就演变成:如何验证一个偶数a是否满足哥德巴赫猜想,即偶数a能否表示为两个素数之和
一个正偶数a一定可以表示为a/2种正整数相加的形式:a=1+(a-1),a=2+(a-2),…a=(a/2-1)+(a/2+1),a=a/2+a/2,一共有a/2种。那么在这a/2种结构种只要存在一种a=i+j, i和j都是素数,就可以判断这个偶数a满足哥德巴赫猜想。

1.3.4 具体实现:判断素数并分解

这里插入一个证明,判断一个数是不是素数a,不需要遍历到a/2,到根号n就可以了。
在这里插入图片描述
首先我们通过函数IsPrime(n)判断数字n是否是质数,然后通过函数GDBH(T)验证大于2的偶数可以分解成2个质数的和,其中参数T是元组,表示需要计算的区间,为了提高程序的运行效率,本程序采用了多线程技术提高效率。具体代码如下:

单线程:

import math
from datetime import datetime


def isPrime(n):
    if n <= 1:
        return False
    else:
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return False
        return True


def GDBH(T):
    S = T[0]
    E = T[1]
    if S < 4:
        S = 4
    if S % 2 == 1:
        S += 1
    for i in range(S, E + 1, 2):
        isGDBH = False
        for j in range(i // 2 + 1):
            if isPrime(j):
                k = i - j
                if isPrime(k):
                    isGDBH = True
                    if i % 10000 == 0:
                        print("%d=%d+%d"%(i, j, k))
                    break
        if not isGDBH:
            print("哥德巴赫猜想错误!")
            break


if __name__ == '__main__':
    start_time = datetime.now()
    GDBH((1, 1000000))
    end_time = datetime.now()
    print(end_time - start_time)

多线程:

import math
from datetime import datetime
from multiprocessing import Pool, cpu_count


def isPrime(n):
    if n <= 1:
        return False
    else:
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return False
        return True


def GDBH(T):
    S = T[0]
    E = T[1]
    if S < 4:
        S = 4
    if S % 2 == 1:
        S += 1
    for i in range(S, E + 1, 2):
        isGDBH = False
        for j in range(i // 2 + 1):
            if isPrime(j):
                k = i - j
                if isPrime(k):
                    isGDBH = True
                    if i % 10000 == 0:
                        print("%d=%d+%d" % (i, j, k))
                    break
        if not isGDBH:
            print("哥德巴赫猜想错误!")
            break


# 对数字空间进行分段CPU_COUNT片
def seprateNum(N, CPU_COUNT):
    list = [[i + 1, i + N // CPU_COUNT] for i in range(4, N, N // CPU_COUNT)]
    list[0][0] = 4
    if list[CPU_COUNT - 1][1] > N:
        list[CPU_COUNT - 1][1] = N
    return list


if __name__ == '__main__':
    N = 10 ** 6
    start_time = datetime.now()
    CPU_COUNT = cpu_count()
    pool = Pool(CPU_COUNT)
    sepList = seprateNum(N, CPU_COUNT)
    res = pool.map(GDBH, sepList)
    pool.close()
    pool.join()
    end_time = datetime.now()
    print(end_time - start_time)
1.3.5 实验结果

在这里插入图片描述
遍历到1000000用时37s,改进程序,使用多线程进行优化。
在这里插入图片描述
关于python多进程相关知识,可以查看这篇博客(留一个小坑,后面补齐!)

1.4 亲密数

1.4.1 问题描述

亲密数的概念:
如果整数a的全部因数之和等于b(此处因数包含1,不包含a),而b的全部因数之和等于a(此处因数包含1,不包含b),那么a和b就是亲密数。

1.4.2 算法分析:穷举法

首先计算出a的全部因数,累加求和得出b的值,再计算b的全部因数累加求和得到res,判断res是否等于a,如果等于,那么a和b就是亲密数。值得注意的是求因数的是对i(i=1~a/2)进行取模运算

1.4.3 具体实现:计算3000以内的亲密数
def check(n):
    """计算各因子之和"""
    res = 0
    for i in range(1, int(n // 2) + 1):
        if n % i == 0:
            res += i
    return res


if __name__ == '__main__':
    for i in range(1, 3000):
        res = check(i)
        if i != res and check(res) == i:
            print(res, i)

1.4.4 输出结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m 宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值