Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 最大回文乘积问题递归中堆栈级别太深(欧拉项目)_Ruby_Recursion_Stack Overflow_Palindrome - Fatal编程技术网

Ruby 最大回文乘积问题递归中堆栈级别太深(欧拉项目)

Ruby 最大回文乘积问题递归中堆栈级别太深(欧拉项目),ruby,recursion,stack-overflow,palindrome,Ruby,Recursion,Stack Overflow,Palindrome,我试图实现一个最大回文乘积的递归解决方案 我试图做的是从999开始,对num1向下迭代到100,然后在999重新启动num1,对num2向下迭代1 目标基本上是模拟嵌套for循环 def largest_palindrome_prod(num1 = 999, num2 = 999, largest_so_far = 0) prod = num1 * num2 largest_so_far = prod if prod > largest_so_far && chec

我试图实现一个最大回文乘积的递归解决方案

我试图做的是从999开始,对num1向下迭代到100,然后在999重新启动num1,对num2向下迭代1

目标基本上是模拟嵌套for循环

def largest_palindrome_prod(num1 = 999, num2 = 999, largest_so_far = 0)
  prod = num1 * num2
  largest_so_far = prod if prod > largest_so_far && check_pal(prod)

  if num2 == 100
    return largest_so_far
  elsif num1 == 100
    largest_palindrome_prod(num1 = 999, num2 -= 1, largest_so_far)
  else
    largest_palindrome_prod(num1 -= 1, num2, largest_so_far)
  end
end

#I know this function works, just here for reference
def check_pal(num)
  num = num.to_s if num.is_a? Integer
  if num.length < 2
    true
  else
    num[0] == num[-1] ? check_pal(num[1..-2]) : false
  end
end
def最大回文量(num1=999,num2=999,最大回文量=0)
产品=num1*num2
最大值=如果prod>最大值(&&check\u pal,prod)
如果num2==100
返回到目前为止最大的\u
elsif num1==100
最大回文量(num1=999,num2-=1,迄今为止最大)
其他的
最大回文量(num1-=1,num2,迄今为止最大)
结束
结束
#我知道这个函数可以工作,这里仅供参考
def check_pal(数字)
num=num.to_s如果num.is_a?整数
如果num.length<2
真的
其他的
num[0]==num[-1]?检查参数(数值[1..-2]):false
结束
结束
rb:10:in
maximust_-palindrome_-prod:堆栈级别太深`


我得到了这个错误,它引用了最大回文prod函数中的else语句,但我不知道wast可能是导致堆栈错误的原因。

您没有无限递归错误。由于输入的大小,堆栈的空间不足。为了证明这一点,您可以使用2位数字而不是3位数字来运行相同的函数。它返回的结果很好,这表明您的逻辑没有缺陷

如何避开这个问题?两种选择

选项1:这里不能使用递归(只需使用常规嵌套循环)

选项2:保留相同的代码并启用尾部调用优化:

# run_code.rb

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}

require './palindrome_functions.rb'
puts largest_palindrome_prod
# => 906609 
注意,出于我不完全理解的原因,尾部调用优化必须在与正在运行的代码不同的文件中启用。因此,如果您只是将compile_选项行移到palindrome_functions.rb文件中,它将无法工作


我真的不能给你一个关于尾部调用优化的完整解释(在维基百科上查找),但是从我的理解来看,这是一个对递归函数的大量优化,只有当递归调用在函数体的末尾时才有效。您的函数符合此条件。

@maxpleaner已经回答了您的问题,并展示了如何使用递归来避免堆栈级错误。他还提到了简单循环而不是使用递归的选项(我希望他喜欢)。下面是一个循环解决方案。以下方法用于搜索1

让我们首先找出960和999之间两个数字乘积的最大回文(如果有):

没有。请注意,此计算非常便宜,只需要检查
40*40/2#=>800
产品。接下来,找到最大的回文,它等于920和999之间两个数字的乘积

check_ranges(920..999)
  #=> 888888
成功!请注意,此方法重新检查我们先前检查的
800
产品。只检查以下两个对
brute\u force
的调用所表示的情况更有意义:

check_ranges(960..999, 920..959)
  #=> 888888 
check_ranges(920..959)
  #=> 861168 
第一次调用计算
40*40#=>1600
产品;第二种,
800
产品

当然,我们还没有找到最大的回文产品。然而,我们对最大的产品有一个下限,我们可以利用这个下限。自

888888/999
  #=> 889
我们推断,如果两个数字的乘积大于
888888
,则这两个数字必须至少为889。因此,我们只需检查:

check_ranges(889..999, 889..919)
  #=> 906609 
check_ranges(889..919)
  #=> 824428 
我们结束了。这告诉我们,
906609
是两个3位数的回文数字的最大乘积

问题并不是问乘积是最大回文的两个数字是什么,但我们很容易找到它们:

(889..999).to_a.product((889..919).to_a).find { |x,y| x*y == 906609 }
  #=> [993, 913] 
993*913
  #=> 906609
此外,让我们:

a = (889..999).to_a.product((889..919).to_a).map { |x,y| x*y }.
      sort.
      reverse
然后:

告诉我们,在找到回文(
906609
)之前,只需检查这组排序后的
111*31#=>3441
产品中最大的
84
元素

所有这些都需要组织成一种方法。虽然对新手来说很有挑战性,但这应该是一次很好的学习经历


一,。测试哪一个更快是有用的,
arr=z位;arr==arr.reverse
s=z.to\s;s==s.reverse

@maxpleaner已经回答了,@Cary Swoveland已经用
范围
产品
展示了一种暴力方式。我想展示另一个使用嵌套循环的蛮力,更容易理解(IMO):


我想它可以进一步优化,例如,使用

n.downto(n*99/100) do |k|
  k.downto(k*99/100) do |j|
在0.7秒内返回
[9997999681199966006699]


不需要,但这会提高速度:

def check_pal(num)
  word = num.to_s
  word.reverse == word
end

您的递归不是达到了900深吗?我认为这远远足以引发堆栈级别太深的异常。请注意,一旦发现
num1*num2
是回文,调用
num1
递减为
1
num2
不变的方法就没有意义了,因为这不会导致更大的回文。您需要在另一个文件中执行此操作的原因是:YARV需要在执行其所有指令之前编译当前文件,因此在编译完所有内容之前,它不知道您的编译选项。@maxpleaner:Is这样做是为了启用尾部递归优化,这是Ruby的官方功能,如果是,记录在哪里?我想知道为什么它不是自动启用的,因为它在相当多的Underlanguages(Erlang,Haskell,…)@user1934428我假设它是“官方”ruby的一个功能,因为它只适用于标准ruby安装。我不知道文档在哪里,我只是在谷歌上找到了那个片段来启用它。我确实看到了在默认情况下启用它的方法“以这种方式启用尾部递归优化,这是Ruby的一个官方特性”——不,它不是。它是一些特定的私有内部实现细节
a.index { |n| n == 906609 }
  #=> 84
n = 9999

res = [0]
bottom = 10**(n.digits.size - 1)

n.downto(bottom) do |k|
  k.downto(bottom) do |j|
    # puts "#{k}, #{j}"
    res = [k, j, k * j] if check_pal(k * j) && k * j > res.last
  end
end

res
#=> [9999, 9901, 99000099]
n.downto(n*99/100) do |k|
  k.downto(k*99/100) do |j|
def check_pal(num)
  word = num.to_s
  word.reverse == word
end