Longest Collatz sequence

本文探讨了一个数学问题:找出在不超过一百万的正整数中,哪个起始数能产生最长的迭代序列,序列规则为偶数除以2,奇数乘3加1,最终皆收敛于1。

https://projecteuler.net/problem=14


The following iterative sequence is defined for the set of positive integers:

nn/2 (n is even)
n → 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million.

这个题本来想从根部1往下找,做一个深度优先搜索,写完代码才发现,小于100万的值,在趋向于的过程中产生的值会比100万大很多,而且我还没法算出来他的上限。

本来已经证明了在生成这颗树的过程中,1不重复出现,那么这棵树的所有值都不会重复。后来想想,及时我知道了上限是多少,生成的这颗树也会有很多多余的节点,也是没有太大的必要。

还是做一个字典吧,从1到100万,都算出来,然后放到字典里面去,这样也算完了,也得到了最大的值,而且中间也不会重复计算,也不会计算多余的值。


def longestChain():
    #准备结果
    result = 0
    #准备步长最大值
    maxstep = 1
    #准备存储字典
    stepdict = {}
    #先把1放进去
    stepdict[1] = 1
    #从1到100万挨个计算
    for i in range(1,1000000):
        #只要i还没有算过,就进行计算
        if i not in stepdict:
            #在i通往1的过程的值都放在列表里面
            templist = [i]
            #获取i的下一个值
            nextValue = nextChain(i)
            #不停的获取下一值,直到这个值在字典中已经存在(已经计算过)
            while nextValue not in stepdict:
                #把还没出现值放到列表里去
                templist.append(nextValue)
                nextValue = nextChain(nextValue)
            #获取i到1的元素个数,如果比最大步长大,就更新一下
            if maxstep < stepdict[nextValue]+len(templist):
                maxstep = stepdict[nextValue]+len(templist)
                result = i
            #把列表中所有出现过的数,都更新到字典中去,值就是步长
            for i in range(0,len(templist)):
                stepdict[templist[i]] = stepdict[nextValue] + len(templist) - i
    return result

def nextChain(n):
    if n % 2 == 0:
        return n // 2
    else:
        return n * 3 + 1
print(longestChain())
                


### 使用 `itertools.zip_longest` 函数 Python 的 `itertools` 模块提供了多种用于高效循环操作的迭代器工具。其中,`zip_longest` 是一个非常有用的函数,它允许两个或多个可迭代对象并行遍历,并在最短序列耗尽之后继续填充指定值。 #### 基本语法 ```python import itertools result = itertools.zip_longest(iterable1, iterable2, fillvalue=None) ``` 此方法接受任意数量的可迭代参数以及一个名为 `fillvalue` 的关键字参数,默认情况下该参数设置为 `None`[^1]。 当输入的可迭代对象长度不一致时,较短的对象会用 `fillvalue` 来补充缺失的位置直到最长的那个结束为止。 #### 实际应用案例 考虑如下场景:有两个列表分别代表不同月份销售量的数据集A和B,但是数据集中某些月可能缺少记录,在这种情况下就可以利用 `zip_longest` 进行处理: ```python from itertools import zip_longest sales_A = ['Jan', 'Feb', 'Mar'] sales_B = [100, 200] for month, sale in zip_longest(sales_A, sales_B, fillvalue=0): print(f"{month}: {sale}") ``` 上述代码将会输出: ``` Jan: 100 Feb: 200 Mar: 0 ``` 这里可以看到三月份并没有实际销售额数值,因此被替换成了默认填充值 `0`。 #### 多个可迭代对象的情况 如果需要同时处理三个以上的可迭代对象,则同样适用: ```python list_a = ["a", "b"] list_b = [1, 2, 3] list_c = ["x", "y", "z"] combined = list(zip_longest(list_a, list_b, list_c)) print(combined) # 输出结果将是 [('a', 1, 'x'), ('b', 2, 'y'), (None, 3, 'z')] ``` 在这个例子中,由于第一个列表只有两项而其他两个各有三项,所以最后一项将由 `None` 补齐以匹配最长序列的长度。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值