【问题标题】:What is the difference between this C++ code and this Python code?这个 C++ 代码和这个 Python 代码有什么区别?
【发布时间】:2014-09-28 21:08:11
【问题描述】:

回答

感谢@TheDark 发现溢出。新的 C++ 解决方案也非常有趣。这是非常多余的:

if(2*i > n && 2*i > i)

替换了旧行代码if(2*i > n)

背景

我正在做this problem on HackerRank,尽管问题可能与这个问题并不完全相关。如果您看不到网页,或者必须注册一个帐户又不想看到,则问题在下面以纯文本形式列出。

问题

我的 C++ 代码超时,但我的 python 代码没有。我一开始怀疑这是因为溢出,但是我用sizeof 确定unsigned long long 可以达到问题的上限2^64 - 1

我实际上将我的 C++ 代码直接翻译成 Python,以查看是否是我的算法导致了超时,但令我惊讶的是,我的 Python 代码通过了所有测试用例。

C++ 代码:

#include <iostream>

bool pot(unsigned long long n)
{
    if (n % 2 == 0) return pot(n/2);
    return (n==1); // returns true if n is power of two
}

unsigned long long gpt(unsigned long long n)
{
    unsigned long long i = 1;
    while(2*i < n) {
        i *= 2;
    }
    return i; // returns greatest power of two less than n
}

int main()
{    
    unsigned int t;
    std::cin >> t;
    std::cout << sizeof(unsigned long long) << std::endl;
    for(unsigned int i = 0; i < t; i++)
    {
        unsigned long long n;
        unsigned long long count = 1;
        std::cin >> n;
        while(n > 1) {
            if (pot(n)) n /= 2;
            else n -= gpt(n);
            count++;
        }
        if (count % 2 == 0) std::cout << "Louise" << std::endl;
        else std::cout << "Richard" << std::endl;
    }
}

Python 2.7 代码:

def pot(n):
    while n % 2 == 0:
        n/=2
    return n==1

def gpt(n):
    i = 1
    while 2*i < n:
        i *= 2
    return i

t = int(raw_input())
for i in range(t):
    n = int(raw_input())
    count = 1
    while n != 1:
        if pot(n):
            n /= 2
        else:
            n -= gpt(n)
        count += 1
    if count % 2 == 0:
        print "Louise"
    else:
        print "Richard"

对我来说,两个版本看起来都一样。我仍然认为我在某种程度上被愚弄了,实际上在我的 C++ 代码中出现溢出,导致超时。

问题

路易丝和理查德玩游戏。他们有一个计数器设置为 N. Louise 获得第一轮,之后轮流交替。在游戏中,他们执行以下操作。

如果 N 不是 2 的幂,则它们会将计数器减少为小于 N 的 2 的最大幂。

如果 N 是 2 的幂,它们会将计数器减少 N 的一半。

结果值是新的 N 再次用于后续操作。

当计数器减少到 1 时,游戏结束,即 N == 1,最后一个有效移动的人获胜。

给定 N,你的任务是找到游戏的获胜者。

输入格式

第一行包含一个整数 T,即测试用例的数量。 T 线紧随其后。每行包含 N,计数器中设置的初始数字。

约束

1≤T≤10

1 ≤ N ≤ 2^64 - 1

输出格式

对于每个测试用例,在新行中打印获胜者的姓名。因此,如果 Louise 赢得比赛,请打印“Louise”。否则,打印“Richard”。 (引号是为了清楚起见)

示例输入

1

6

样本输出

理查德

解释

由于 6 不是 2 的幂,Louise 将 2 的最大幂减少到小于 6 即 4,因此计数器减少为 2。

由于 2 是 2 的幂,Richard 将计数器减半,即 1。因此计数器减为 1。

当我们达到 N == 1 的终止条件时,Richard 赢得了比赛。

【问题讨论】:

  • 为什么不将 c++ 中的递归 pot 调用替换为 Python 代码中使用的相同 while loop 版本?
  • @GWW 我试过了,但大多数测试用例仍然超时。
  • "1 ≤ N ≤ 264 - 1" - 你确定那是对的……不是 2^264 之类的吗?对于 264,它的计算速度非常快,而且 C++ 代码运行良好。
  • 我尝试了从 1 到 264 的所有值,它运行得很快。可能超时与他们的编译器的 c++ cin 速度慢有关?
  • 它应该说 2^64,而不是 264。抱歉,复制/粘贴混乱。

标签: python c++ algorithm python-2.7


【解决方案1】:

试试这个小技巧,它可能会稍微快一点:

unsigned long largest_power_of_two_not_greater_than(unsigned long x) {
  for (unsigned long y; (y = x & (x - 1)); x = y) {}
  return x;
}

x&amp;(x-1)x 没有它的最低有效一位。所以y 将在x 减少到2 的幂时为零(终止循环),这将是不大于原始x 的2 的最大幂。对于x 中的每个 1 位,循环执行一次,平均迭代次数是您的方法的一半。此外,这个没有溢出问题。 (如果原始 x 为 0,则返回 0。这可能是也可能不是您想要的。)

请注意,如果原始 x 是 2 的幂,则该值会立即返回。因此,该函数兼作测试 x 是否为 2(或 0)的幂。

虽然这很有趣,但在现实生活中的代码中,您最好找到与此 gcc 内置函数等效的编译器(除非您的编译器 gcc,在这种情况下是):

  • 内置函数:int __builtin_clz (unsigned int x) 返回X 中前导 0 位的数量,最多开始 重要位的位置。如果X 为 0,则结​​果未定义。

(对于 unsigned long 参数也可作为 __builtin_clzl 使用,对于 unsigned long long 也可使用 __builtin_clzll。)

【讨论】:

  • 这东西真的很酷。它完全让我想起了基数排序之类的东西。
【解决方案2】:

n 大于 2^63 时,您的 gpt 函数最终会将 i 设为 2^63,然后将 2^63 乘以 2,产生溢出和值为 0。然后以无限循环结束,每次将 0 乘以 2。

【讨论】:

    猜你喜欢
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2020-12-26
    • 1970-01-01
    相关资源
    最近更新 更多