我的代码中是否存在无限循环来解决Collat​​z序列?

时间:2013-12-26 20:32:53

标签: ruby

我的代码试图找到这个问题的答案:为正整数集定义了以下迭代序列:

n → n/2 (n is even)
n → 3n + 1 (n is odd)

使用上面的规则并从13开始,我们生成以下序列:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

可以看出,该序列(从13开始,在1结束)包含10个术语。虽然尚未证实(Collat​​z问题),但据认为所有起始数字都以1结束。

哪个起始编号低于一百万,产生最长的链?

注意:一旦链条启动,条款允许超过一百万。

这是我的代码:

step_count = 1
score = {}
largest_score = 1
(1..1000000).map do |n|
  while n >= 1 do
    if n%2 == 0 then
      n/2
      step_count += 1
    else
      (3*n)+1
      step_count += 1
    end
  end
  score = {n => step_count}
end
score.each {|n, step_count| largest_score = step_count if largest_score < step_count}
puts score.key(largest_score)

我跑了一个多小时仍然没有回答。我的代码中是否存在无限循环,或者可能存在一些不同的问题,如果是这样,它是什么?

我正在使用Ruby 1.8.7

2 个答案:

答案 0 :(得分:4)

是的,你有一个无限循环。就在这里:

while n >= 1 do
  if n%2 == 0 then
    n/2
    step_count += 1
  else
    (3*n)+1
    step_count += 1
  end
end

while循环中的条件是测试n,但循环中没有任何内容正在更改其值。你可能想要做的是:

while n >= 1 do
  if n % 2 == 0
    n = n / 2
    step_count += 1
  else
    n = (3 * n) + 1
    step_count += 1
  end
end

一些旁注:

  • 看起来你的意思是用新的键值对更新score哈希值,但正如所写,score = { n => step_count }将在每次迭代时完全替换它。要将新对添加到现有哈希,请使用score[n] = step_count
  • 通过在哈希中查找比使用其他方式更高效,因此您可能想要撤消哈希存储:{{ 1}},找到score[step_count] = n的最大分数并使用score.each { |step_count, n| #...读取。这有一个额外的好处,你不必存储所有数百万的结果;它只会存储您到达的最后一个数字,从而产生给定长度的链。当然,它也意味着你只会看到一个导致最大链的数字,即使有多个数字具有相同的最高链长!问题的措辞似乎是答案是独一无二的,但如果不是,你就不会发现。
  • 要在将来调试这样的问题,将循环迭代放到微小的东西(十,比方说)并在循环中撒一些score[largest_score]语句以观察正在发生的事情并感受执行情况是很方便的流动。

答案 1 :(得分:0)

针对您的问题尝试以下解决方案:

def solve(n)
  max_collatz = 0; max_steps = 0
  (1..n).each do |k|
    next if k % 2 == 0
    next if k % 3 != 1
    steps = collatz_sequence_count(k)
    if steps > max_steps
      max_steps   = steps
      max_collatz = k
    end
  end
  max_collatz
  # answer: 837799 with 525 steps, in nearly 2.2 seconds on my machine
end

def collatz_sequence_count(k)
  counter = 1
  while true
    return counter if k == 1
    k = k % 2 == 0 ? k/2 : 3 * k + 1
    counter += 1
  end
end

# You can then use the above methods to get your answer, like this:
answer = solve 1000000
puts "answer is: #{answer}"

结果(使用自定义自酿宝石来解决ProjectEuler问题):

nikhgupta at MacBookPro in ~/Code/git/ProjectEuler [ master: ✗ ] 48d
± time euler solve 14                                                                                             +next: 2 | total: 22 | ▸▸▸▹▹▹▹▹▹▹
0014 | Longest Collatz sequence | It took me: 2.166033 seconds. | Solution: 837799
euler solve 14  3.30s user 0.13s system 99% cpu 3.454 total