【问题标题】:Ruby: Mutating method parameters (integer vs. array)Ruby:变异方法参数(整数与数组)
【发布时间】:2018-01-10 11:12:16
【问题描述】:

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

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

然而,在这种情况下,情况并非如此,计数器变量被重新分配给内存中的一个新值(无论结果整数指向的位置)。

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

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

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 pass-by-reference pass-by-value


    【解决方案1】:

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

    解决方案

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

    2) 不要在combination_sum4 的末尾返回counter。将generate_combinations 保留为方法的最后一行。无论它返回什么,combination_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
    

    【讨论】:

    • 嗯——如果可能的话,想看看解决方案!最好不要使用实例/全局变量,尽管这是一个简单的解决方案。
    • @Sunny 更新了答案,希望对您有所帮助!
    • += 1 现在不需要了(只会增加混乱)
    • 不错的收获,感谢@SergioTulentsev。 (1..nums.length).each 也应该是 nums.each。仅当数字按[1,2,3,4...](1..nums.length).each 排序时才有效
    【解决方案2】:

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

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

    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
    

    【讨论】:

      猜你喜欢
      • 2015-12-21
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2010-10-30
      • 2013-03-24
      • 2014-07-29
      • 1970-01-01
      • 2012-09-20
      相关资源
      最近更新 更多