在字符串中找到完美的正方形
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 > 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 - 在给定的大数范围内找到所有完美正方形的最快方法