我的意大利面酱里有什么?


37

背景

在法国以及可能在欧盟其他地区,任何可供出售的食品都必须在其包装上列出其成分,并按重量百分比降序排列。但是,除非成分由文字或封面上的图像突出显示,否则不必指示确切的百分比

例如,我的罗勒番茄酱在包装上仅显示一些大红色西红柿和美丽的罗勒叶,具有以下指示:

成分:西红柿80%,洋葱片,罗勒1.4%,海盐,蒜泥,生蔗糖,特级初榨橄榄油,黑胡椒。

听起来很美味,但是…… 到底要吃多少洋葱

挑战

给定重量百分比降序列表(最终不完整),输出可能在配方中找到的最小最大重量百分比的完整列表。

  • 您可以编写函数或完整程序。
  • 输入可以是任何合理的形式(数字或字符串列表的阵列,例如)。分数值应至少支持小数点后一位。如果丢失一个重量百分比可以在任何一致和明确的方式来表示(0'?'或者null,例如)。你可以假定输入总是会关联到一个有效的配方([70][∅, ∅, 50]无效,例如)。
  • 所述输出可以是任何合理的形式(一个阵列两者的最小和最大重量百分比,或双峰的单个列表的,例如)。最小百分比和最大百分比可以任意顺序([min, max]并且[max, min]都可以接受)。确切的重量百分比无需与其他百分比进行不同的处理,可以用相等的最小和最大值表示。

适用于标准规则:在您键入代码时,我的面食正在冷却,因此最短的提交者获胜。

例子

由于此问题比乍看之下要困难得多,因此,这是一些情况的逐步解决方案。

[40, ∅, ∅]

咱们分别调用xy两名失踪的百分比。

  • 因为它紧随第一成分之后为40%,x所以本身不能高于40%。
    [40, [?, 40], [?, ?]]
  • 这两个缺失百分比之和始终为60%。所以 :
    • 如果x取其最大值,则y取其最小值,因此为60%-40%= 20%。
      [40, [?, 40], [20, ?]]
    • 如果x取其最小值,则y取其最大值。但x不能低于y,因此在这种情况下x= y= 60%/ 2 = 30%。
      [40, [30, 40], [20, 30]]

[70, ∅, ∅, 5, ∅]

让我们分别叫xyz三个缺失的百分比。

  • 的最小和最大百分比z必须在0%到5%之间。让我们z暂时假设= 0%。这两个缺失百分比之和始终为25%。所以 :
    [70, [?, ?], [?, ?], 5, [0, 5]]
    • 如果y取其最小值 5%,则x取其最大值,即25%-5%= 20%。
      [70, [?, 20], [5, ?], 5, [0, 5]]
    • 如果y取其最大值,则x取其最小值。但x不能低于y,因此在这种情况下x= y= 25%/ 2 = 12.5%。
      [70, [12.5, 20], [5, 12.5], 5, [0, 5]]
  • 让我们验证一下,假设现在z等于5%,一切都很好。这两个缺失百分比的总和始终为20%。所以 :
    • 如果y取其最小值 5%,则x取其最大值,即20%-5%= 15%。这种情况已包含在先前计算的范围内。
    • 如果y取其最大值,则x取其最小值。但是x不能低于y,因此在这种情况下x= y= 20%/ 2 = 10%。该案例已经包含在的先前计算范围内y,但不包含在之中x
      [70, [10, 20], [5, 12.5], 5, [0, 5]]

测试用例

Input:  [∅]
Output: [100]

Input:  [70, 30]
Output: [70, 30]

Input:  [70, ∅, ∅]
Output: [70, [15, 30], [0, 15]]

Input:  [40, ∅, ∅]
Output: [40, [30, 40], [20, 30]]

Input:  [∅, ∅, 10]
Output: [[45, 80], [10, 45], 10]

Input:  [70, ∅, ∅, ∅]
Output: [70, [10, 30], [0, 15], [0, 10]]

Input:  [70, ∅, ∅, 5, ∅]
Output: [70, [10, 20], [5, 12.5], 5, [0, 5]]

Input:  [30, ∅, ∅, ∅, 10, ∅, ∅, 5, ∅, ∅]
Output: [30, [10, 25], [10, 17.5], [10, 15], 10, [5, 10], [5, 10], 5, [0, 5], [0, 5]]


3
我想补充的输入到输出的一步一步的解释[40, ∅, ∅],并[70, ∅, ∅, 5, ∅]让事情有点更清晰。在不查看测试用例的情况下应该明确挑战,目前情况并非如此。如果我正确理解以下内容[40, ∅, ∅]:100%需要60以上,再除以这两个。第一个必须为30或更高(否则第二个将在其之上,当按顺序排列时这不可能)。此外,它不能在上方40,因此第一个变为[30,40],第二个变为[(100-40-40=)20, (100-40-30=)30]
凯文·克鲁伊森

一致[min,max]/ [max,min]或混合允许?
l4m2 '18年

@ l4m2混合[min,max][max,min]可以接受边界,但是由于它不会导致模棱两可的结果,因此我想这是可以的。
黑洞

也许我缺少了一些东西,但是为什么[70, 12, 11, 5, 2]第二个例子不起作用?如果确实有效,则的最小值x将小于12.5
DLosc '18年

Answers:


11

JavaScript(ES6),252个字节

期望0缺少百分比。返回所有条目的一对最小值和最大值。

a=>(g=a=>(h=(M,I,J=I^1)=>a.some((x,i)=>a.map((y,j)=>s-=j-i?M(j,i)-i?y[I]:M(w=y[I],z=x[J])-z||w==z?w:++k&&z:y[J],s=100,k=1,X=x)&&(I?-s:s)<0)?X[J]=M(X[I],X[J]+s/k):0)(Math.max,0)+h(Math.min,1)?g(a):a)(a.map((n,i)=>[n?p=n:a.find(n=>i--<0&&n)||0,p],p=100))

在线尝试!

怎么样?

初始化

我们首先用尽可能大的范围替换输入数组a []中的每个值。

a.map((n, i) =>       // for each value n at position i in a[]:
  [                   //   generate a [min, max] array:
    n ?               //     if n is not 0:
      p = n           //       use n as the minimum and save it in p
    :                 //     else:
      a.find(n =>     //       find the first value n
        i-- < 0 &&    //         which is beyond the current value
        n             //         and is not equal to 0
      ) || 0,         //       or use 0 as a default value
    p                 //     use p as the maximum
  ],                  //   end of array declaration
  p = 100             //   start with p = 100
)                     // end of map()

例子:

[ 0 ] --> [ [ 0, 100 ] ]
[ 30, 0, 5, 0 ] --> [ [ 30, 30 ], [ 5, 30 ], [ 5, 5 ], [ 0, 5 ] ]

主功能

主要功能是h()。当我们试图最小化或最大化它时,它将寻找似乎不一致的第一个条目。如果找到一个,则在给定其他范围的情况下,将其更新为至少暂时可接受的值。

它以M = Math.max / I = 0M = Math.min / I = 1作为输入,并将J定义为I XOR 1

由于编写了h()来支持最小化和最大化传递,因此代码注释起来有些棘手。这就是为什么我们只关注最大化通过的原因,为此,我们有M = Math.maxI = 0J = 1。使用这些参数,代码如下:

a.some((x, i) =>              // for each range x at position i in a[] (tested range):
  a.map((y, j) =>             //   for each range y at position j in a[] (reference range):
    s -=                      //     update s:
      j - i ?                 //       if i is not equal to j:
        Math.max(j, i) - i ?  //         if j > i:
          y[0]                //           the reference range is beyond the tested range
                              //           so we just use the minimum value of the y range
        :                     //         else:
          Math.max(           //           take the maximum of:
            w = y[0],         //             w = minimum value of the y range
            z = x[1]          //             z = maximum value of the x range
          ) - z ||            //           if it's not equal to z
          w == z ?            //           or they are equal (i.e. if w <= z):
            w                 //             use w
          :                   //           else:
            ++k && z          //             increment the counter k and use z
      :                       //       else:
        y[1],                 //         use the maximum value of the y range
    s = 100,                  //     start with s = 100
    k = 1,                    //     start with k = 1
    X = x                     //     save the range x in X
  ) &&                        //   end of map()
  (0 ? -s : s) < 0            //   abort if s < 0 (i.e. if we've subtracted more than 100)
) ?                           // end of some(); if truthy:
  X[1] = Math.max(            //   update the maximum value of the faulty range to:
    X[0],                     //     either the minimum value
    X[1] + s / k              //     or the maximum value, less the correction
  )                           //   whichever is greater
:                             // else:
  0                           //   do nothing

递归

递归函数g()一直调用h(),直到最小化或最大化传递均未导致新的校正,并最终返回最终结果。

g = a => h(Math.max, 0) + h(Math.min, 1) ? g(a) : a

做得很好 :-) !
黑洞

4
@Blackhole谢谢!顺便说一句:我自己的意大利面酱读[38,0,10,0,0,0,0,0,0,0]
阿诺尔德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.