大点符号pt 1初学者指南

When we write code, it’s important to understand how our choice of code impacts the speed and performance of the program we’re creating. Big O Notation is a way to classify how quickly the runtime of the algorithm/number of operations or space increases in relation to the input n. It looks at the worst case scenario, assuming every possible element is touched on as the algorithm is written.

在编写代码时,重要的是要了解我们的代码选择如何影响所创建程序的速度和性能。 大O表示法是一种方法,用于分类算法的运行时间/操作数或空间相对于输入n 。 它考虑了最坏的情况,假设在编写算法时触及了每个可能的元素。

There are seven classifications in Big O Notation, ranging from fantastic, fast and/or space efficient solutions that remain constant despite the input size, to absolutely terrible, please-don’t-ever-use-these solutions!

Big O符号有7种分类,从输入量不变的奇妙,快速和/或节省空间的解决方案,到绝对可怕的,请不要使用这些解决方案!

Understanding how different data structures and algorithms fit into this Big O complexity gradient can help you select the right ones and optimize your code at work — or for a tech coding interview, perhaps.

了解不同的数据结构和算法如何适应这个大O复杂度梯度可以帮助您选择合适的数据结构和算法,并在工作中优化代码,或者进行技术编码面试。

O(1)恒定时间 (O(1) Constant Time)

Let’s say that you’re Chef Remy and you’ve been asked to cook your world famous Ratatouille.

假设您是雷米(Remy)厨师,并且被要求煮世界闻名的料理鼠王(Ratatouille)。

chef Remy cooking ratatouille
Yum! Image credit: Pixar
好吃图片来源:皮克斯

The first thing you do is gather the ingredients, spices and herbs to prepare the dish. The kitchen is your second home — you know exactly where to find everything you need:

您要做的第一件事是收集食材,香料和草药以准备菜肴。 厨房是您的第二故乡–您确切地知道在哪里可以找到所需的一切:

let kitchen = {
vegetables: {
broccoli: {name: "broccoli", ...},
zucchini: {name: "zucchini", ...},
eggplant: {name: "eggplant", ...},
carrot: {name: "carrot", ...},
squash: {name: "squash", ...},
tomato: {name: "tomato", ...},
radish: {name: "radish", ...},
cabbage: {name: "cabbage", ...},
redPepper: {name: "redPepper", ...}
},
seasoning: {
onion: {name: "onion", ...},
garlic: {name: "garlic", ...},
basil: {name: "basil", ...},
oregano: {name: "oregano", ...},
herbesDeProvence: {name: "herbesDeProvence", ...},
sage: {name: "sage", ...},
ginger: {name: "ginger", ...}
}
}

You don’t need everything in the kitchen for this recipe — broccoli and ginger don’t belong in ratatouille after all!️ Instead, you grab only the ingredients you need, like this:

您不需要厨房中的任何东西即可制作此食谱-西兰花和生姜毕竟不属于料理鼠王!️相反,您只抓住了需要的食材,像这样:

let ingredients = []ingredients.push(kitchen.vegetables.zucchini.name)
ingredients.push(kitchen.vegetables.eggplant.name)
ingredients.push(kitchen.vegetables.squash.name)
ingredients.push(kitchen.vegetables.tomato.name)
ingredients.push(kitchen.vegetables.redPepper.name)ingredients.push(kitchen.seasoning.onion.name)
ingredients.push(kitchen.seasoning.garlic.name)
ingredients.push(kitchen.seasoning.herbesDeProvence.name)// ingredients = ["zucchini", "eggplant", "squash", "tomato", "redPepper", "onion", "garlic", "herbesDeProvence"]

What would the Big O notation time complexity of those operations be? 🤔

这些操作的Big O表示法时间复杂度是多少? 🤔

Each of these operations (grabbing the ingredient, pushing it into the ingredients array) takes constant time, or O(1). The number of operations doesn’t grow with the size of the array or the size of the kitchen object. We have direct access to each element to grab exactly what we need, so the time complexity does not change.

这些操作(抓取成分,将其推入ingredients数组)中的每一个都需要恒定的时间,即O(1)。 操作的数量不会随着数组的大小或厨房对象的大小而增加。 我们可以直接访问每个元素以准确获取我们需要的内容,因此时间复杂度不会改变。

Here’s another example:

这是另一个例子:

function addDigitsUpToNumber(n) {
return n * (n + 1) / 2
}addDigitsUpToNumber(5) // 15, same as 1 + 2 + 3 + 5 = 15

In this function, we add up all of the digits, from 1 to n, and return the sum by using a quick math trick. This function also has O(1) time complexity because it takes the exact same number of operations regardless of whether n is equal to 5, 10, 1,000 or 1,000,000,000.

在此函数中,我们将所有数字加起来,从1到n ,并使用快速数学技巧返回总和。 此函数还具有O(1)时间复杂度,因为无论n是等于5、10、1,000还是1,000,000,000,它都需要执行相同数量的运算。

O(n)线性时间 (O(n) Linear Time)

To start preparing ratatouille, you first have to chop the ingredients:

要开始准备料理鼠王,首先需要切碎成分:

let ingredients = ["zucchini", "eggplant", "squash", "tomato", "redPepper", "onion", "garlic", "herbesDeProvence"]function makeRatatouille(ingredients) {
function chop() {
for (let i = 0; i < ingredients.length; i++) {
console.log(`${ingredients[i]} has been chopped!`)
}
}
}

How long should our makeRatatouille function take to complete? Better yet, how many operations need to take place? 🤔

我们的makeRatatouille函数需要多长时间才能完成? 更好的是,需要进行多少次操作? 🤔

Since there are seven elements in our ingredients array and the function iterates through each one once (chopping as we go), we could say that seven operations need to take place (O(7)). If we added additional n ingredients to our array, this function would take n operations since it needs to touch upon each one of those elements once, otherwise known as O(n).

由于我们的ingredients数组中有七个元素,并且函数在每个元素中迭代一次(切入时进行切入),因此可以说需要进行七个操作(O(7))。 如果我们向数组中添加其他n成分,则此函数将执行n操作,因为它需要一次接触这些元素中的每个元素,否则称为O(n)。

O(n) time complexity is also known as linear time and is generally considered an efficient solution. It isn’t as good or as fast as O(1) or O(log n), which we’ll get to later, but usually this time complexity is considered acceptable.

O(n)时间复杂度也称为线性时间 通常被认为是一种有效的解决方案。 它不如我们稍后将讨论的O(1)或O(log n)那样好或快,但是通常认为这种时间复杂度是可以接受的。

What would happen if we added another iteration? After all, those ratatouille ingredients need to roast in the oven!

如果再添加一次迭代会怎样? 毕竟,那些料理鼠王的成分需要在烤箱中烤!

chef Remy prepping the ratatouille for roasting
Image credit: Pixar
图片来源:皮克斯
let ingredients = ["zucchini", "eggplant", "squash", "tomato", "red pepper", "onion", "garlic"]function makeRatatouille(ingredients) {
function chop() {
for (let i = 0; i < ingredients.length; i++) {
console.log(`${ingredients[i]} has been chopped!`)
}
} function roast() {
for (let i = 0; i < ingredients.length; i++) {
console.log(`${ingredients[i]} has been roasted!`)
}
}
}

Our makeRatatouille function now needs to iterate through all of the ingredients twice: First, in the chop function, then again in the roast function. We could say this function takes O(2n) time, since it will iterate through the ingredients array exactly twice.

现在,我们的makeRatatouille函数需要对所有成分进行两次迭代:首先,在chop函数中,然后再在roast函数中。 我们可以说此函数需要O(2n)时间,因为它将对配料数组精确地进行两次迭代。

The time complexity of this function still grows in proportion to n, so we would remove any constants (the number 2 in this case) and call this O(n), just as before. Even if this function had additional operations that came out to O(4n + 20), for example, we would still shorten this to say O(n), because in Big O notation, constants and smaller operations aren’t counted.

该函数的时间复杂度仍然与n成正比,因此我们将删除所有常量(在这种情况下为2),并像以前一样将其称为O(n)。 例如,即使此函数具有附加的运算O(4n + 20),我们仍将其简称为O(n),因为用大O表示法不包括常数和较小的运算符。

O(n²)二次时间 (O(n²) Quadratic Time)

As Chef Remy, you hear that famed restaurant critic (and notorious grump) Anton Ego is coming to judge your food for the first time. Yikes! 😰

作为大厨雷米(Remy),您会听到著名的餐厅评论家(和臭名昭著的脾气暴躁)安东·埃格(Anton Ego)第一次来评判您的食物。 kes! 😰

anton ego gif
Image credit: Pixar
图片来源:皮克斯

He will accept only the best, so you decide to sort through all your chopped vegetables to find the best ones for his ratatouille. Let’s pretend that each slice has a rating from 1–n, with 1 being the best slice and n being the worst:

他只会接受最好的,所以您决定对所有切碎的蔬菜进行分类,以找到最适合他的料理鼠王的蔬菜。 假设每个切片的评分范围为1–n,其中1为最佳切片,n为最差切片:

let zucchiniSlices = [20, 11, 25, 3, 14, 5,...]function sortByBestSlices(veggieSlices) {
for (let i = 0; i < veggieSlices.length; i++) {
for (let j = 0; j < veggieSlices.length; j++) {
if (veggieSlices[i] < veggieSlices[j]) {
let temp = veggieSlices[i];
veggieSlices[i] = veggieSlices[j];
veggieSlices[j] = temp;
}
}
}
return veggieSlices
}sortByBestSlices(zucchiniSlices)

The time complexity for this function is pretty bad. Here we’re looking at O(n²), also known as quadratic time because we have a nested for loop situation. In this function we are iterating through each slice in our veggieSlices array, comparing it to all other slices one by one, as n * n. If the array had 30 slices, we would have 30 x 30 operations (900). If we had 100 slices, to sort them this way would take 10,000 operations!

此功能的时间复杂度很差。 这里我们看的是O(n²),也称为二次时间 因为我们有一个嵌套的for循环情况。 在此函数中,我们遍历veggieSlices数组中的每个切片,并将其与所有其他切片逐个比较,即n * n 。 如果数组有30个切片,我们将有30 x 30的运算(900)。 如果我们有100个切片,以这种方式对其进行排序将需要10,000次操作!

The runtime could grow pretty fast — and Anton Ego is waiting for his meal! Isn’t there a more efficient way to sort, that has less impact on the runtime?

运行时间可能会很快增长-Anton Ego正在等他的饭! 是否有一种更有效的排序方式,对运行时间的影响较小?

Of course there is!

当然有!

There are many algorithms that are much faster than O(n²), such as those that run in O(log n) and O(n log n) time. We’re going to explore those in Part 2 of this series.

有许多算法比O(n²)快得多,例如那些以O(log n)和O(n log n)时间运行的算法。 我们将在本系列的第2部分中进行探讨。

In the meantime let’s pour another glass of wine for Anton Ego and hope he stays patient. 🍷 Stay tuned!

同时,让我们为安东·自我再倒一杯酒,希望他保持耐心。 🍷敬请期待!

anton ego waiting gif
Image credit: Pixar
图片来源:皮克斯

Update: Check out part 2 where we dive into O(log n), O(n log n), O(2^n) and O(n!) here!

更新:看看第2部分,我们深入到O(log n)的,为O(n log n)的,O(2 ^ n)和O(N!)在这里

翻译自: https://medium.com/better-programming/a-beginners-guide-to-big-o-notation-pt-1-19ec031b698b

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值