Ruby:改变方法参数(整数与数组)

Ruby: Mutating method parameters (integer vs. array)

提问人:segue_segway 提问时间:8/3/2017 更新时间:8/3/2017 访问量:1208

问:

在下面的代码中,我的初衷是将计数器变量传递给递归运行的帮助程序方法,并在此过程中更新它,然后在帮助程序函数完成运行时返回它。

计数器返回零,我试图弄清楚为什么会这样。我知道这种方法在传入数组时有效,我相信这是因为对数组的每个引用都指向内存中的同一对象,例如,当您使用 shovel 运算符时,您正在改变该对象。

然而,在这种情况下,情况并非如此,计数器变量被重新分配给内存中的新值(无论生成的整数指向何处)。

这是我的问题 - >这里的问题是计数器变量被正确重新分配,但仅在其定义的范围内?因此,返回的“counter +=1”不会保留对计数器变量的更改,因为在该函数的范围内(并且仅在函数的范围内)重新分配了计数器变量?很难彻底理解这一点。以下是有兴趣的人的问题陈述:

给定一个包含所有正数且没有重复项的整数数组,请找到加起来为正整数目标的可能组合数。

Example:

nums = [1, 2, 3]
target = 4

The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.

Therefore the output is 7.

这是我的代码:

# @param {Integer[]} nums
# @param {Integer} target
# @return {Integer}
def combination_sum4(nums, target)
    nums.sort! # n log n 
    generate_combinations(nums, target, counter = 0)
    counter
end

def generate_combinations(nums, target, counter)
    return counter += 1 if target == 0
    (1...nums.length).each do |num|
        break if num > target
        generate_combinations(nums, target - num, counter)
    end 
    counter
end 
Ruby 按引用传递

评论


答:

0赞 m. simon borg 8/3/2017 #1

这是一个范围问题。您传入的局部变量与其内部变量不同。方法中定义的局部变量的范围限定为该方法。当您将它们传递给另一个方法时,您传递的是变量的值,而不是变量本身。在 内部,永远不会改变其原始值 。countergenerate_combinationscountercombination_sum4counter0

解决 方案

1)使用实例变量,只要这些方法在同一上下文中或在同一类或模块上定义,就可以由这些方法共享。如果稍后需要在后续方法调用期间访问相同的值,这将很有帮助。@counter

2)不要在末尾返回。保留为方法的最后一行。无论它返回什么,也会被 返回。countercombination_sum4generate_combinationscombination_sum4

def combination_sum4(nums, target)
  nums.sort! # n log n 
  generate_combinations(nums, target)
end

def generate_combinations(nums, target, counter = 0) # `counter` is now an optional argument with a default value of `0`
  return counter + 1 if target.zero?
  nums.each do |num| # use inclusive range (..) rather than exclusive range (...)
    break if num > target
    counter = generate_combinations(nums, target - num, counter) # reassign `counter` to the return value of the recursion
  end 
  counter
end

评论

0赞 segue_segway 8/3/2017
嗯 - 如果可能的话,希望看到解决方案!最好不要使用实例/全局变量,尽管这是一个简单的解决方案。
0赞 m. simon borg 8/3/2017
@Sunny 更新了答案,希望对您有所帮助!
0赞 Sergio Tulentsev 8/3/2017
现在没有必要了(只会增加混乱)+= 1
0赞 m. simon borg 8/3/2017
不错的收获,谢谢@SergioTulentsev。也应该只是.它仅在数字排序时有效(1..nums.length).eachnums.each[1,2,3,4...](1..nums.length).each
0赞 romainsalles 8/3/2017 #2

@m-simon-borg 完美地解释了您的问题:您有一个范围问题。

但是,我建议使用(@see:https://ruby-doc.org/core-2.1.0/Enumerable.html#method-i-reduce)来执行此操作的“rubyest”方法:inject

def combination_sum4(nums, target)
  generate_combinations(nums.sort, target, 0)
end

def generate_combinations(nums, target, counter)
  return counter += 1 if target == 0

  (1..nums.length).inject(counter) do |counter, num|
    num > target ?
      counter : 
      generate_combinations(nums, target - num, counter)
  end
end

nums = [1, 2, 3]
target = 4
combination_sum4(nums, target) # 7