Project Euler Problem 14 (C++和Python代码实现和解析)

Problem 14 : Longest Collatz sequence

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

n → n/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. 第14个问题: 最长的Collatz序列

下面迭代(重复)的序列被定义为正整数的集合:

n → n/2 (n 是偶数)
n → 3n + 1 (n 是奇数)

使用上面的规则,从13开始,我们能产生下面的序列:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

可以看出,这个序列从13开始,到1结束,包含10个项。虽然它还没有被证明(Collatz 猜想),人们认为所有的起始数都在1结束。

小于一百万,哪个起始的数,产生最长的链?

注意: 一旦链开始,所有的项都允许超过100万。

2. 求解分析

这道题可能有比较巧妙的方法来实现,但我们还是先使用暴力枚举来求解。

可以分解为两个函数:

第一函数:任何一个起始数都有一个产生一个Collatz序列,计算序列的项的个数。

第二个函数:起始数从1到100万,依次计算Collatz序列的项的个数,找到项数最大的Collatz序列的起始数。

3. C++ 代码实现

我们看看PE0014的类图:
在这里插入图片描述

成员函数getNumOfTermsOfCollatzSequence(int startingNumber) 获取每一个起始数的Collatz序列的项的个数。

成员函数getLongestCollatzChain(int maxStartingNumber) 找到小于最大起始数的最长的Collatz序列。

C++ 代码

#include <iostream>
#include <cassert>

using namespace std;
    
//#define UNIT_TEST

class PE0014
{
public:
    int getLongestCollatzChain(int maxStartingNumber);
    int getNumOfTermsOfCollatzSequence(int startingNumber);
};

int PE0014::getLongestCollatzChain(int maxStartingNumber)
{
    int longestChainTerms = 0;
    int longestChainStartingNumber;
    int numOfTerms;

    for (int number=maxStartingNumber-1; number>=1; number--)
    {
        numOfTerms = getNumOfTermsOfCollatzSequence(number);

        if (longestChainTerms < numOfTerms)
        {
            longestChainTerms = numOfTerms;
            longestChainStartingNumber = number;
        } 
    }

#ifdef UNIT_TEST
    cout << "Starting number " << longestChainStartingNumber <<", under " ;
    cout << maxStartingNumber << ", produces the longest chain containing " ;
    cout <<  longestChainTerms << " terms" << endl;
#endif

    return longestChainStartingNumber;
}

int PE0014::getNumOfTermsOfCollatzSequence(int startingNumber)
{
    long long n = startingNumber;
    int numOfTerms = 1;

    while (n != 1)
    {
        if (n % 2 == 0) // n is even
        {
            n /= 2;
        }
        else            // n is odd
        {
            n = 3*n+1; 
        }
        numOfTerms ++;
    }

    return numOfTerms;
}

int main()
{
    PE0014 pe0014;

    assert(10 == pe0014.getNumOfTermsOfCollatzSequence(13));

    cout << "Starting number " << pe0014.getLongestCollatzChain(1000000) ;
    cout << ", under 1000000, produces the longest Collatz chain." << endl;

    return 0;
}

4. Python 代码实现

Python采用了和C++一样的方法。同样也由两个函数getTermsOfCollatzSequence() 和 getLongestCollatzSequence()来完成。

Python 代码

def getTermsOfCollatzSequence(startingNumber):
    n, mumOfTerms = startingNumber, 1
    while n != 1:
        if 1 == n % 2:
            n = 3*n+1
        else:
            n = n//2
        mumOfTerms += 1
    return mumOfTerms
    
def getLongestCollatzSequence(maxStartingNumber):
    maxNumOfTerms = 0
    for n in range (1, maxStartingNumber):
        numOfTerms = getTermsOfCollatzSequence(n)
        if numOfTerms > maxNumOfTerms:
            startingNumber = n
            maxNumOfTerms  = numOfTerms
    return startingNumber
    
def main():
    assert 10 == getTermsOfCollatzSequence(13)
    print("Starting number %d" % getLongestCollatzSequence(10**6), end='')
    print(", under one million, produces the longest Collatz chain.")

if  __name__ == '__main__':
    main()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值