在字符串中找到完美的正方形

Posted

技术标签:

【中文标题】在字符串中找到完美的正方形【英文标题】:Find the perfect square in the string 【发布时间】:2013-02-14 10:22:19 【问题描述】:

一个完美的正方形被取为二进制,一些位被替换为“?”例如 1??,数字将是 4.(或 1????000???0000)

我需要找到那个完美的正方形。(只有这样可能的数字)

字符串中 '?' 的个数为 n

要找到这个数字,我正在做的是遍历 2**n 个数字(111,110,101,100)并检查它是否是一个完美的正方形。我正在使用以下函数来检查它是否是一个完美的正方形。

bool issqr(int n)
   int d=(int)(sqrt(n));
   if(d*d==n) return true;
   else return false;

虽然我在 python 中做到了,但它需要很多时间,所以我转移到 C++,只使用位操作来填充 2**n 个数字(这比 python 版本快得多)

但如果数字超过 64 位,则会失败

如何避免这个问题?如果一个数字有 120 位,我怎么能做同样的事情。

(10100110???1?1?01?1?011000?1100?00101000?1?11001101100110001010111?0?1??0110?110?01?1100?1?0110?1?10111?01?0111000 ?10??101?01)

【问题讨论】:

除了最高位之外都被“?”替换了还是可以有更复杂的模式,例如 1??1??1 请添加一个120位的例子 这类问题的制定,使得蛮力是不合理的。它们需要数学简化和算法洞察力。 【参考方案1】:

您应该首先考虑改进算法,而不是用 C++ 重写。最低可能的答案是原始值的平方根,所有“?”替换为四舍五入的 0,可能的最高答案是模式的平方根,将 '? 替换为向下舍入的 1。找到这两个值,遍历它们,平方并检查模式。

这更快,因为您迭代的数字要少得多,而且因为您没有在循环中计算任何平方根:平方要容易得多。

你不需要比较字符串来检查匹配:

mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
test = int(pattern.replace('?', '0'), 2)

def is_match(n):
    return (n&mask)==test

所以把它们放在一起:

def int_sqrt(x):
    if x < 0:
        raise ValueError('square root not defined for negative numbers')
    n = int(x)
    if n == 0:
        return 0
    a, b = divmod(n.bit_length(), 2)
    x = 2**(a+b)
    while True:
        y = (x + n//x)//2
        if y >= x:
            return x
        x = y

def find_match(pattern):
    lowest = int(pattern.replace('?', '0'), 2)
    highest = int(pattern.replace('?', '1'), 2)
    mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
    lowsqrt = int_sqrt(lowest)
    if lowsqrt*lowsqrt != lowest:
            lowsqrt += 1
    highsqrt = int_sqrt(highest)
    for n in range(lowsqrt, highsqrt+1):
        if (n*n & mask)==lowest:
            return n*n

print(find_match('1??1??1'))
print(find_match('1??0??1'))
print(find_match('1??????????????????????????????????????????????????????????????????????1??0??1'))

输出:

121
81
151115727461209345152081

注意这仅适用于 Python 3.x,最后一个测试将在 Python 2.x 中溢出range

【讨论】:

如果一个数字有 120 位并且说 70 “?”检查数字是否具有相同的模式需要更多时间,因为我在这里处理字符串。相反,我只喜欢具有相同模式的数字。 如果数字有 120 位,您将不得不编写自己的 sqrt 或使用大数字库。 如果你有 120 位和 70 个“?”那么任何类型的搜索都需要很长时间。 @Duncan 我不能使用按位运算,对吗?如何更改代码的最后两行? 为什么不能使用按位运算?这似乎是一个奇怪的限制【参考方案2】:

据我了解,给定一个整数 n,您正试图找到一个平方数 sq 匹配:

2n - 1 n+1 - 1

这个条件是“我的号码必须是 1????”的数学翻译。哪里有n“?”。

首先,您可以注意到,如果n 是偶数,则数字 2n 是一个完全平方并且符合您的条件(在二进制中,它是数字 1000...000 - n零 -)。

如果n 是不均匀的(比如n = 2.p + 1),那么2n+1 是一个完美的正方形((2p+1) 2)。计算以下数字将为您提供一个完美的正方形:

(2p+1 - 1)2

要满足第一个不等式,p 必须满足:

2n - 1 p+1 - 1)2

然后

0 n+1 - 2p+2 + 1 - 2n + 1,

最后,

2n + 2 - 2p+2 > 0 或者 22p - 2p+1 + 1 > 0

如果我们考虑将 p 与 f(p) 匹配的函数:

f(p) = 22p - 2p+1 + 1

这个函数是为每个正实数定义的,并且是严格递增的。此外,f(0) = 0。最后,当p &gt; 0 时满足初始条件! 对于p = 0 - 或n = 1 -,问题没有有效的解决方案。

【讨论】:

@Anil 我在您编辑问题之前发布了答案。你接受的答案是你最好的选择【参考方案3】:

你不需要遍历所有的 2**n 个数字来找到完美的平方,实际上你只需要一个小数平方操作:

假设您有整数 n,并且您想找到小于或等于 n 的最大完美正方形,我们将其称为 m。 那么:

d = (int)sqrt(n);
m = d*d;

解释:

假设有一个完美的正方形 m' 比 m 大,这意味着有一个整数 d' 使得:d' > d 并且 d'*d' = m'。

但是 d' >=d+1 和 (d+1)*(d+1) > n 所以 m' > n 与我们的要求 m'

现在回答你的问题:

为了找到完美的正方形,只需将所有“?”更改为“1”。并找到完美的正方形,如果它符合你的字符串,你得到了你正在寻找的数字,如果没有改变足够的“?”从 msb 到 "0" 使结果数小于或等于您刚刚找到的完美正方形,并继续前进,直到找到完美正方形或用完选项。

【讨论】:

问题中不清楚除了一位之外的所有内容是否都被问号替换(在这种情况下您的答案是正确的),或者是否可能存在诸如1??0??1 之类的模式哪种情况会更复杂。 @Eli Algranti 并不是说​​您只会有一个这样的数字,即使那样它也可能没有相同的位模式。 抱歉在完成答案之前一直点击保存 @Eli 问题不在于算法,而在于处理 120 位整数。 @Anil 你在 python 上是如何应对的?为此,您需要编写自己的大数字库(不是一件容易的事)或使用可用的库(例如 gmplib.org/manual/Integer-Roots.html#Integer-Roots)【参考方案4】:

您的操作可能返回对于整数来说太大的东西... http://www.cplusplus.com/doc/tutorial/variables/

【讨论】:

你的回答是错误的。位域结构不能超过 int 的大小。

以上是关于在字符串中找到完美的正方形的主要内容,如果未能解决你的问题,请参考以下文章

Python - 在给定的大数范围内找到所有完美正方形的最快方法

找到大约 300 位排列的所有完美正方形

当 Python 中的输入是大数时,如何有效地在一个范围内找到完美的正方形

有没有办法找到下一个完美的正方形?

在查找c ++范围内的完美正方形时由于超时错误而终止

几何-完美正方形:百科