Ruby挑战:有经验的开发者意见

时间:2014-01-21 20:50:33

标签: ruby rspec

我正在研究面向新开发人员的一些红宝石问题,但我希望有经验的开发人员对此提出意见。对不起,我很感谢你的时间和意见。

问题

  

编写一个函数nearest_larger(arr, i),它接受​​一个数组和一个   指数。该函数应返回另一个索引j:这应该   满足:

     
      
  • (a)arr[i] < arr[j],AND
  •   
  • (b)j2i相比j更接近arr[i] < arr[j]
  •   
     

如果是关系(参见下面的示例),请选择最早(最左侧)   这两个指数。如果arr中的号码不大于arr[i],   返回nil

     

难度:2/5

Rspec测试

describe "#nearest_larger" do
  it "handles a simple case to the right" do
    nearest_larger([2,3,4,8], 2).should == 3
  end

  it "handles a simple case to the left" do
    nearest_larger([2,8,4,3], 2).should == 1
  end

  it "treats any two larger numbers like a tie" do
    nearest_larger([2,6,4,8], 2).should == 1
  end

  it "should choose the left case in a tie" do
    nearest_larger([2,6,4,6], 2).should == 1
  end

  it "handles a case with an answer > 1 distance to the left" do
    nearest_larger([8,2,4,3], 2).should == 0
  end

  it "handles a case with an answer > 1 distance to the right" do
    nearest_larger([2,4,3,8], 1).should == 3
  end

  it "should return nil if no larger number is found" do
    nearest_larger( [2, 6, 4, 8], 3).should == nil
  end
end

解决方案

def nearest_larger arr, idx
diff = 1
  loop do
    l = idx - diff
    r = idx + diff
    return l    if (l >= 0) && (arr[l] > arr[idx])
    return r    if (r < arr.length) && (arr[r] > arr[idx])
    return nil  if (l < 0) && (r >= arr.length)
    diff += 1
  end
end

反馈

  1. 您将如何努力寻求解决此问题的方法? (你的过程是什么?)
  2. 在您看来,确实发现问题清晰且易于理解?
  3. 解决这个问题需要多长时间? (10分钟,20分钟,......?)
  4. 是否同意难度? (请记住,这是针对新开发人员的)
  5. 如果愿意:请发布您自己的解决方案,展示您解决此问题的方式。
  6. 我决定发布这个问题,因为我知道新开发人员遇到问题并且不知道先写什么是多么容易。我希望您的回复能够让您深入了解如何解决您认为是挑战的问题。

2 个答案:

答案 0 :(得分:2)

我没有经验丰富的开发人员,甚至没有经验丰富的开发人员,但无论如何我都会给你我的想法。

1您将如何努力寻找解决此问题的方法? (你的流程是什么?)

我希望分手,但肯定每个人都这样做。例如,这里数组中的值仅用于拉出较大元素的索引,因此我认为第一个问题是拉出索引,第二个问题是单独处理索引。我将通过从每个索引中减去i来进一步简化后者,以便jk进行比较,如下所示:if j.abs < k.abs ...,而不是if (j-i).abs < (k-i).abs...。在选择不同的方法时,我倾向于寻找最容易理解的方法(“最佳读取”)。

2。您认为问题问题是否清晰且易于理解?

第3。你需要多长时间才能解决这个问题?

我拒绝回答是因为它肯定会使我入罪。

4。你同意难度吗?

看来是对的。这将是rubeque.com的“初学者”问题。

5。如果愿意:请发布您自己的解决方案,展示您解决此问题的方式。

不确定

def nearest_larger(arr, i)
  ret = nearest_to_zero( arr.each_with_index
                            .select { |e,j| e > arr[i] }
                            .map    { |_,j| j-i        } )
  ret ? ret + i : nil
end

我看了两种写作方式nearest_to_zero()。第一种是简短,直接且清晰,但效率低下,使用sort!

def nearest_to_zero(a)
  a.sort! { |j,k| (j.abs == k.abs) ? j <=> k : j.abs <=> k.abs }
  a.any? ? a.first : nil
end

效率更高,但不是很漂亮:

def nearest_to_zero(a)
  neg, pos = a.partition { |e| e < 0 }    
  case
  when neg.empty?
    pos.empty? ? nil : pos.first
  when pos.empty?
    neg.last
  else
    pos.last.abs < neg.last.abs ? pos.first : neg.last
  end 
end

对于arr = [2,5,4,8,10], i = 2,以下步骤由nearest_larger()执行:

a   = arr.each_with_index.select { |e,j| e > arr[i] } # => [[5,1],[8,3],[10,4]] 
b   = a.map { |_,j| j-i }                             # => [-1,1,2] 
ret = nearest_to_zero(b)                              # => -1 
ret ? ret + i : nil                                   # => 1 

在第一个nearest_to_zero()中,如果两个索引具有相等的绝对值(意味着它们在转换之前同样接近i),则平局将转到具有较低值的索引;否则它是绝对值较小的索引。

在第二个nearest_to_zero()中:

neg, pos = [-1,1,2].partition {|e| e < 0} #  => [[-1],[1,2]]

其余的应该是不言自明的。

我读过有关rspec的内容,但之前没有使用过它。这是时候了。我的代码通过了。

答案 1 :(得分:1)

  

您将如何努力寻找解决此问题的方案? (你的过程是什么?)

从一个简单的例子开始,例如其中一项测试。我们发现,如果数组元素arr[i-1]大于arr[i],那么您可以立即返回i-1作为答案。所以你可以连续检查:i-1, i+1, i-2, i+2, i-3, i+3等并返回满足不等式的第一个索引。

  

您认为问题问题是否清晰易懂?

是;测试有所帮助,但它只是证实了我对措辞问题的理解。

  

解决这个问题需要多长时间? (10分钟,20分钟,......?)

对于测试/课堂环境中的学生,不超过10分钟。取决于他们之前有多少准备材料,甚至可能更少。

  

是否同意难度? (请记住,这是针对新开发人员的)

是的,2/5似乎是对的。

  

如果愿意:请发布您自己的解决方案,展示您解决此问题的方式。

def nearest_larger( a, i )
  2.upto([i,a.length-i].max << 1) do |k|
    j = (k&1).zero? ? i - (k>>1) : i + (k>>1)
    return j if 0 <= j && j < a.length && a[i] < a[j]
  end
  return nil
end

附录:在比特中思考

本附录将更详细地介绍为新程序员的利益而进入上述解决方案的问题解决方法。

正如上面问题#1的回答中所提到的,nearest_larger的返回值是第一个索引ja[i] < a[j]j遍历序列

i-1, i+1, i-2, i+2, i-3, i+3, ...

这打开了一个子问题的方法,即如何生成这个数字序列。在实际编写程序时,我使用了注释作为&#34;便笺簿&#34;,并在代码中有这样的内容:

# -1, 1, -2, 2, -3, 3, ...            (Sequence G)

通过向每个术语添加i来构造先前序列。调用此序列G.现在这是一个二元直觉&#34;会发挥作用。考虑一个简单的二进制数序列,在每个术语后增加1,如A列所示,熟悉的十进制表示在B列中显示:

   A   B     C   D   E   F
----------------------------
0000   0   000   0   0   0
0001   1   000   1   0   0
0010   2   001   0   1  -1
0011   3   001   1   1   1
0100   4   010   0   2  -2
0101   5   010   1   2   2
0110   6   011   0   3  -3
0111   7   011   1   3   3

现在将每个数字中的位分成两组:除了位0之外的所有位(最右位),如列C所示,位0显示在列D中。换句话说,连接C和D得到A. C的十进制表示在E列中。请注意,D列方便地在0和1之间翻转,就像在序列G中一样,数字在负数和正数之间翻转。我们将使用它来构造列F,它与E相同,除非当D为0时使F为负。最后,如果我们刚开始在A = 0010(或B = 2)的上表中,那么F列给出了上面的序列G.

那么现在我们如何在代码中从A中获取F列?这就是位操作的用武之地。

C = A >> 1 - >> right-shift operator通过RHS(右侧)移动LHS(左侧)的位。在这种情况下,每个值A移动到右边的一个位置。最右边的位丢失了。在数学上,它与除以2相同并且在这种情况下丢弃余数(B / 2 == E,其余部分被删除。)

D = A & 1 - &bitwise AND operator。通过&#34; anding&#34; A为1,我们只选择0位;有关详细信息,请参阅前一句中的链接。这给了我们D列。

将这些放在代码中,我们将k作为迭代变量,从2开始,每次递增1。然后上面的分析给了我们j

j = (k&1).zero? ? i - (k>>1) : i + (k>>1)

j的第一个值(在a[i] < a[j]范围内且return j if 0 <= j && j < a.length && a[i] < a[j] 保留的值自动为答案,因此可以立即返回:

j

最后,如果nil没有有效值,则返回k。除了计算作为家庭作业问题的nearest_larger的下限上限之外,这是{{1}}函数的全部。

在实际操作中,对于这样的问题,OP中提出的可读解决方案是优选的,因为它对于更广泛的程序员组来说更清楚和可访问。目前的方法是有机会展示位操作的使用。