帆布指纹_单一化简功能解决帆布技术难题

帆布指纹

This is part of a series called “Refactoring Javascript: Collection Pipelines.” You can read the introduction here.

这是称为“重构Javascript:集合管道”的系列的一部分。 您可以在此处阅读介绍。

In a previous article, I gave an introduction to the power of reduce(), however, I didn’t really highlight it’s potential with a real world example.

在上一篇文章中 ,我对reduce()的功能进行了介绍,但是,在实际示例中,我并没有真正强调它的潜力。

In this article we will solve the Canva technical challenge using a single reduce function.

这篇文章中,我们将使用一个单一的减少功能解决Canva技术挑战。

Note: In the event that Canva is still using this question to screen candidates, be aware that they use HackerRank to check for plagiarism, don’t try to submit this answer.

注意:如果Canva仍在使用此问题来筛选候选人,请注意他们使用HackerRank检查窃, 请勿尝试提交此答案。

挑战 (The Challenge)

The task is to write an algorithm that takes two parameters. The first parameter is an array of integers (a), the second is an integer (k). You are asked to return the length of the longest subarray within a, such that the sum of its elements is less than or equal to k.

任务是编写一个采用两个参数的算法。 第一个参数是整数( a)的数组,第二个参数是整数( k )。 要求您返回a中最长子数组的长度,以使其元素之和小于或等于k。

A subarray of an n-element array is an array composed from a contiguous block of the original array’s elements. For example, if a = [1,2,3], then the subarrays are [1],[2],[3],[1,2] ,[2,3] , and [1,2,3]. Something like [1,3] would not be a subarray as it’s not a contiguous subsection of the original array.

n元素数组的子数组是由原始数组元素的连续块组成的数组。 例如,如果a = [1,2,3] ,则子数组为[1],[2],[3],[1,2],[2,3]和[1,2,3] 。 像[1,3]这样的东西将不是子数组,因为它不是原始数组的连续子节。

天真的解决方案 (The Naive Solution)

There is a very inefficient but straightforward solution to this problem. We can iterate through the array, taking the sum at each iteration. If sum ≤ k then we keep going. Whenever we exceed k we store the max size, remove the first element of the array and repeat the process. The solution might look something like this

有一个非常低效但简单的解决方案。 我们可以遍历数组,在每次迭代中取和。 如果总和≤k,那么我们继续前进。 每当我们超过k时,我们都会存储最大大小,删除数组的第一个元素,然后重复该过程。 解决方案可能看起来像这样

const maxLength = (a, k) => {let currentMax = 0;let runningSum = 0;let i = 0;while (a.length > 0) {if (runningSum + a[i] <= k) {if (i > currentMax) currentMax = i;
runningSum += a[i];
} else {
i = 0;
runningSum = 0;
a.shift();
}
}return currentMax;
};

This code is kind of gross and I didn’t submit it or run it through any tests but you get the overall picture of the solution. We keep looping over the array until we run out out of subarrays.

这段代码很粗糙,我没有提交它或通过任何测试运行它,但您了解了该解决方案的总体情况。 我们一直循环遍历数组,直到用尽子数组为止。

We can even implement this naive solution using only map(), filter() and reduce() but given the solution is grossly inefficient I won’t bother explaining it. A picture of a possible implementation is included here for reference.

我们甚至可以只使用map(),filter()和reduce()来实现这种幼稚的解决方案,但是鉴于该解决方案的效率非常低下,我不会在此进行解释。 此处包括可能的实现方式的图片,以供参考。

Image for post
Terrible solution using a collection pipeline of maps
使用地图收集管道的糟糕解决方案

If you don’t understand what is happening in the code above, you should go execute each map function individually and log the result.

如果您不了解上面的代码中发生了什么,则应分别执行每个map函数并记录结果。

聪明的解决方案 (The Clever Solution)

This task only requires that we return the length of the largest subarray. If you think carefully about the problem you might see it is possible to solve it with only a single iteration over the input array. I’ll do my best to explain the algorithm…..

该任务仅要求我们返回最大子数组的长度。 如果仔细考虑问题,您可能会发现仅需对输入数组进行一次迭代即可解决该问题。 我将尽力解释该算法…..

// Let's take a simple example for a and kconst a = [1,0,0,1,0,1,0,2]
const k = 2
// We start at element 0, if the value is <= k we try to drag a "window" right - increasing the size of the window, otherwise we shift the window right and adjust our total. dragging increases the window size, shifting just moves the window through the array.// Example: (window shown in bold)[1,0,0,1,0,1,0,2] // Total = 1, drag right, windowSize = 1[1,0,0,1,0,1,0,2] // Total = 1, drag right, windowSize = 2[1,0,0,1,0,1,0,2] // Total = 1, drag right, windowSize = 3[1,0,0,1,0,1,0,2] // Total = 2, drag right, windowSize = 4[1,0,0,1,0,1,0,2] // Total = 2, drag right, windowSize = 5[1,0,0,1,0,1,0,2] // Total = 3, shift right, windowSize = 5[1,0,0,1,0,1,0,2] // Total = 2, drag right, windowSize = 6[1,0,0,1,0,1,0,2] // Total = 4, end of array, windowSize = 6// Once we hit the end of the array we can stop as we know that we've got the largest possible window we can have. We can see in this example that the largest subArray was 6

By increasing the windowSize for any valid subArray summing to less than k we know that a subArray of that length exists somewhere. When the sum is >k we can just shift the window across without increasing its size. When we hit the end of the array the windowSize will be the same length of the largest subArray summing to ≤k

通过增加windowSize对于任何有效的子阵的总和为少于k个我们知道,该长度的一个子某处。 当总和> k时,我们可以在不增加窗口大小的情况下移动窗口。 当我们击中数组的末尾时,windowSize将与最大子数组的长度相同,总和为≤k

We can encode this logic in a single reduce function as follows

我们可以将这个逻辑编码为单个reduce函数,如下所示

Image for post
using a single reduce function
使用单个减少功能

There’s a lot to unpack here. With reduce() functions it’s good to start at the default value.

这里有很多要解压的东西。 使用reduce()函数,最好从默认值开始。

{
total: 0,
start: 0,
windowSize: 0,
}

We’ll have access to this object (and update it) at every item in the array. We’re tracking a total, start and windowSize.

我们将在数组中的每个项目上都可以访问(并更新)该对象。 我们正在跟踪总计,开始和windowSize。

The parameters of reduce

减少参数

a.reduce(
(acc, curr, _, arr) =>

Reduce gives us access to 4 things. acc is the accumulator, basically the thing we pass to each step. curr is the current item in the array, the third parameter we don’t need so have labelled it as _, but it is the index of the current item, arr is the original array. Check MDN if you want to find out more.

减少使我们可以访问4件事。 acc是累加器,基本上是我们传递给每一步的东西。 curr是数组中的当前项目,我们不需要第三个参数,因此已将其标记为_,但它是当前项目的索引, arr是原始数组。 如果您想了解更多信息,请检查MDN

A Predicate (conditional)

谓词(有条件的)

acc.total + curr <= k

If we take the accumulated total, and add the current value, is it ≤ k?

如果我们取累加的总数,然后加上当前值,它是否≤k?

I’ve used a ternary here for conciseness.

为了简洁起见,我在这里使用了三进制

Dragging the Window

拖动窗口

// Total + current <= k
? {
...acc,
total: acc.total + curr,
windowSize: acc.windowSize + 1,
}

If the running total + current value is less than k we want to update the running total, and increment the window size by one. We keep the start index the same. This is achieved by spreading the old accumulated object, while updating the total, and window size.

如果运行总计+当前值小于k,我们要更新运行总计,并将窗口大小增加一。 我们保持起始索引不变。 这是通过扩展旧的累积对象,同时更新总数和窗口大小来实现的。

Shifting the Window

移窗

// Total + current > k
: {
...acc,
total: acc.total - arr[acc.start] + curr,
start: acc.start + 1,
}),

If the running total + current value exceeds k then we need to leave the windowSize unchanged and shift the window right (increment the start index by 1). We then need to update the running total of the window by removing the value of the element that dropped out when we shifted right, and adding the value of the new element.

如果运行总数+当前值超过k,则需要保持windowSize不变,并向右移动窗口(将起始索引增加1)。 然后,我们需要通过删除右移时丢失的元素的值并添加新元素的值来更新窗口的运行总计。

那就是所有的人 (That’s All Folks)

I hope you enjoyed this solution and have an improved understanding of what’s possible with reduce(). You can replace nearly any loop in your (Java/Type)script code with a map(), filter(), or reduce().

我希望您喜欢这个解决方案,并更好地了解reduce()的功能。 您可以用map(),filter()或reduce()替换(Java / Type)脚本代码中的几乎所有循环。

If you want to learn more about refactoring your JS code to leverage collection pipelines, you can pre-order my book for just $10 here

如果您想了解有关重构JS代码以利用收集管道的更多信息,可以在这里以10美元的价格预订我的书

翻译自: https://medium.com/@Michael_Timbs/solving-canvas-technical-challenge-with-a-single-reduce-function-731245b80101

帆布指纹

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值