【问题标题】:Euler Project #1 in R欧拉项目#1 R
【发布时间】:2014-03-08 08:55:54
【问题描述】:

问题

找出所有能被 3 或 5 整除的小于 1000 的数字的总和

我创建的一个解决方案:

x <- c(1:999)
values <- x[x %% 3 == 0 | x %% 5 == 0]
sum(values

第二个解决方案我无法上班,需要帮助。我已经把它贴在下面了。 我正在尝试使用循环(在这里,我使用 while(),然后我将尝试 for())。我仍在努力将索引(向量中的位置)的引用与向量中的值/观察值分开。循环似乎让我更难区分这两者。

为什么这不能产生 Euler #1 的答案?

x <- 0
i <- 1
while (i < 100) {
  if (i %% 3 == 0 | i %% 5 == 0) {
    x[i] <- c(x, i)
  }  
  i <- i + 1
}
sum(x)

用文字来说,这就是我所理解的正在发生的事情:

  1. x 的值为 0
  2. i 得到值 1
  3. 虽然对象 i 的值(不是索引 #)是
  4. 如果能被 3 或 5 整除
  5. 将数字 i 添加到向量 x
  6. 按顺序将 1 添加到 i(以保持循环达到定义的 1e3 限制
  7. 对向量 x 中的所有项求和

我猜 x[i]

【问题讨论】:

  • 解决保持索引和值分离问题的更通用方法是更具描述性的名称。尽管i 是标准的索引,但您也可以将其用作数字。在这个例子中,你可以打电话给inumbers_to_testxsuccesses,这样你就不用费力去记住是什么了。

标签: r for-loop while-loop


【解决方案1】:

首先,您的循环一直运行到i &lt; 100,而不是i &lt; 1000

其次,将x[i] &lt;- c(x, i)替换为x &lt;- c(x, i),为向量添加一个元素。

【讨论】:

  • 是的,感谢您了解这一点(100 对 1000)。好的,所以没有必要使用 [] 来表示我想将一个项目添加到向量中,对吗?通常我认为 x
  • @jmo 你的理解是正确的。每次,您都将x 替换为一个新的(更长的)向量。
  • 啊,它刚刚点击。谢谢!一段时间以来,我一直在面对各种练习题(我不会承认多久 :) 试图真正“得到它”。我现在知道了。谢谢!
【解决方案2】:

这是我认为给出相同答案的替代方案(使用 99 而不是 999 作为上限):

iters <- 100
x <- rep(0, iters-1)
i <- 1

while (i < iters) {
  if (i %% 3 == 0 | i %% 5 == 0) {
    x[i] <- i
  }  
  i <- i + 1
}
sum(x)

# [1] 2318

这里是原帖中提到的for-loop

iters <- 99
x <- rep(0, iters)
i <- 1

for (i in 1:iters) {
  if (i %% 3 == 0 | i %% 5 == 0) {
    x[i] <- i
  }  
  i <- i + 1
}
sum(x)

# [1] 2318

【讨论】:

    【解决方案3】:

    还有一种方式:

    x <- 1:999
    sum(which(x%%5==0 | x%%3==0))
    # [1] 233168
    

    【讨论】:

      【解决方案4】:

      这是一个执行这个求和的捷径,这可能更符合问题的精神:

      3*(333*334/2) + 5*(199*200/2) - 15*(66*67/2)
      ## [1] 233168
      

      这就是为什么会这样:

      在整数集合[1,999]中有:

      333 个可被 3 整除的值。它们的总和为 3*sum(1:333)3*(333*334/2)

      199 个可被 5 整除的值。它们的总和为 5*sum(1:199)5*(199*200/2)

      将这些相加得到一个因它们的交集而过高的数字,即可以被 15 整除的值。有 66 个这样的值,它们的总和是 15*(1:66)15*(66*67/2)

      作为 N 的函数,可以写成:

      f <- function(N) {
        threes <- floor(N/3)
        fives  <- floor(N/5)
        fifteens <- floor(N/15)
      
        3*(threes*(threes+1)/2) +  5*(fives*(fives+1)/2) - 15*(fifteens*(fifteens+1)/2)
      }
      

      给予:

      f(999)
      ## [1] 233168
      f(99)
      ## [1] 2318
      

      【讨论】:

      • 这很整洁。我不确定,但我认为该函数甚至可以推广到任何两个除数,即使用 a、b 和 c 代替 3、5 和 15。
      • @MarkMiller 除非您可以证明,否则我认为您的条件还不够,因此我将回滚您的编辑。当然对于 ab prime 是有效的。
      • @MatthewLundberg 当 n = 20 时,我测试了 a 和 b 的大约 15 种组合的编辑,它总是给出正确的答案。我会将编辑放在我自己的帖子中。
      • @mark 尝试 10 和 14,限制为 1000。我想你会看到这是一个反例。而且我不同意您将我的内容作为您自己的答案,因为这与 Sven 所做的完全不同。但是,您可以使用自己的答案做您想做的事情。
      • @MatthewLundberg 我认为我从未听说过有人反对其他人推广开源代码。不过,如果您觉得这样做侵犯了您的内容,我不会打扰。我现在没有时间测试代码以确定素数之外存在哪些限制,但以后可能会这样做。
      【解决方案5】:

      一个非常高效的方法如下:

      div_sum <- function(x, n) {
        # calculates the double of the sum of all integers from 1 to n 
        # that are divisible by x
        max_num <- n %/% x
        (x * (max_num + 1) * max_num)      
      }
      
      n <- 999
      a <- 3
      b <- 5
      
      (div_sum(a, n) + div_sum(b, n) - div_sum(a * b, n)) / 2
      

      相比之下,一个非常的代码如下:

      x=1:999
      sum(x[!x%%3|!x%%5])
      

      【讨论】:

      • @MatthewLundberg 是的,这与您的答案相似。我只是从我在玩欧拉问题时发现的解决方案中复制它。我不想让你不高兴,但分享我的答案。当然,如果您愿意,我会删除我的答案。请告诉我。
      • 不用担心。请注意,此解决方案要求 ab 互质。
      • @MatthewLundberg 感谢您指出这一点。我没有意识到这一点。所以,这不是一个通用解决方案。
      猜你喜欢
      • 1970-01-01
      • 2017-07-20
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多