So the answer to this question is the first one.
Fifteen.
Or in general in an N.
Element array the largest number of inversions is N.
Choose two.
Also known as N times N minus one over two.
Which, again, in the case of a [inaudible] is going to evaluate to fifteen.
The reason is, the worst case is when the array is in backwards order, reverse [inaudible] order, and every single pair of [inaudible] indices is inverted.
And so the number of indices IJ, with I less than J is precisely [inaudible] too.
Let's now turn our attention to the problem of computing the number of inversions of an array as quickly as possible.
So one option that is certainly available to us is the brute force algorithm.
And by brute force I just mean we could set up a double four loop.
One which goes through I, one which goes through J bigger than I, and we just check each pair IJ individually with I less than J whether that particular pair of array entities AI and AJ is inverted and if it is then we add it to our running count.
And then we return the final count at the end of the double four loop.
That's certainly correct.
The only problem is, as we just observed, there's N [inaudible] two or a quadratic number of potential inversions so this algorithm's almost going to run in time quadratic in the array link.
Now remember the mantra of any good algorithm designer.
Can we do better? And the answer is yes.
And the method we'll be using, divide and conquer.
The way in which we'll divide will be motivated directly by merge sort where we recurs e separately on the left and the right half's of the array.
We're gonna do the same thing here.
To understand how much progress we can make purely using recursion let's classify the inversions of array into one of three types.
So suppose we have an inversion of an array I, J, and remember in an inversion you always have I less than J.
We're gonna call it a left inversion.
If both of the array indices are at most N over two, where N is the array length.
We're gonna call it a right inversion if they're both strictly greater than N over two.
And we're gonna call it a split inversion if the smaller index is at most N over two and the larger index is bigger than N over two.
We can discuss the progress made by recursion in these terms.
When we recurse on the left-half of an array, if we implement our algorithm correctly, we'll successfully be able to count all of the inversions located purely in that first half.
Those are precisely the left inversions.
Similarly, a second recursive call on just the right half of an array, the second half of an [inaudible] array will successfully count all of the right inversions.
There remains the questions of how to count the split inversions.
But we shouldn't be surprised there's some residual work left over, even after the recursive calls do their job.
That, of course, was the case at Merge Short, where [inaudible] magically took care of sorting the left half of the array, sorting the right half of the array.
But there was still, after their return, the matter of merging those two sorted lists into one.
And here again, after the recursion is gonna be the matter of cleaning up and counting the number of split inversions.
So for example if you go back to the six element array we worked through before, 135246, you'll notice that there, in fact, all of the inversions are split.
So the recursive calls will both come back counting zero inversions.
And all of the work for that example will be done by the count split inversions subroutine.
So let's summarize where things stand given underspecified high level description of the algorithm as we envision it.
There is a base case.
I'll go ahead and write it down for completeness, which is if we're given a one element array, then there's certainly no inversion so we can just immediately return the answer zero.
For any bigger array, we're going to divde and conquer.
So we'll count the left inversions with a recursive call.
The right inversions with a recursive call.
And then we'll have some currently unimplemented subroutine that counts the split inversions.
Since every inversion is either left or right, or split, and can't be any more than one of those three, then, having done these three things, we can simply return their sum.
So that's our high level attack on how we're gonna count up the number of inversions.
And of course, we need to specify how we're gonna count the number of split inversions.
And moreover, we lack that subroutine to run quickly.
An analogy to emerge short, where, outside the recursive calls, we did merely linear work.
Outs-, in the merge subroutine.
Here, we'd like to do only linear work in counting up the number of split inversions.
If we succeed in this goal, if we produce a correct and linear time of limitation to count up the number of split incursions, then this entire recursive algorithm will run in big O.
Of N.
Log in time.
The reason the overall out rhythm will run in O.
Of N.
Log in time is exactly the same reason that merge short ran in N.
Log in time.
There's two recursive calls.
Each on a problem of one-half the size.
And outside of the recursive calls we would be doing linear work.
So you could copy down exactly the same recursion tree argument we used for merge short.
It would apply equally well here.
Alternatively, very soon we will cover the master method, and as one very special case it will prove that this algorithm, if we can implement it thusly, will run in O.
Of N.
Log in time.
Now one thing to realize, is this is a fairly ambitious goal, to count up the number of split inversions in linear time.
It's not that there can't be too many split inversions.
There can actually be a lot of them.
If you have an array where the first half of the array contains the numbers N over two plus one, up to N.
Whereas the second part of the array contains the numbers one up to N over two, that has a quadratic number of inversions, all of which are split.
So, what we're attempting to do here is count up a quadratic number of things using only linear time.
Can it really be done? Yes is can, as we'll see in the next video.
因此,這個問題的答案是第一個。
十五。
或一般在N。
元素數(shù)組的最大反轉(zhuǎn)數(shù)為N。
選擇兩個。
也稱為N乘N減二乘一。
同樣,在[聽不清]的情況下,結(jié)果將為15。
原因是,最壞的情況是當數(shù)組按向后順序,[聽不清]反向,并且每對[聽不清]索引都被反轉(zhuǎn)時。
因此,索引IJ(I小于J)的數(shù)量也正是[聽不清]。
現(xiàn)在,讓我們將注意力轉(zhuǎn)向盡快計算數(shù)組的求逆數(shù)的問題。
因此,我們當然可以使用的一種選擇是蠻力算法。
通過蠻力,我只是說我們可以建立一個雙四環(huán)。
穿過I的一個,穿過J的一個大于I的,我們只是單獨檢查每對IJ,而我的I小于J,則這對特定的數(shù)組實體AI和AJ是否反轉(zhuǎn)了,如果是,則將其添加到我們的數(shù)組中運行計數(shù)。
然后,我們在雙四循環(huán)的末尾返回最終計數(shù)。
這是正確的。
就像我們剛剛觀察到的那樣,唯一的問題是,存在N個[聽不清]兩個或二次數(shù)的潛在求逆,因此該算法幾乎將在數(shù)組鏈接中以二次時間運行。
現(xiàn)在,請記住任何優(yōu)秀算法設計師的口頭禪。
我們可以做得更好嗎?答案是肯定的。
我們將使用的方法是劃分和征服。
劃分方式將直接由合并排序驅(qū)動,合并排序是在數(shù)組的左半部分和右半部分分別遞歸e。
我們將在這里做同樣的事情。
要了解僅使用遞歸就可以取得多少進展,讓我們將數(shù)組的倒置分類為三種類型之一。
因此,假設我們有一個數(shù)組I,J的求逆,并且記住在求逆中,我的I總是小于J。
我們將其稱為左反轉(zhuǎn)。
如果兩個數(shù)組索引的最大值都大于2,則N是數(shù)組長度。
如果它們都嚴格大于N大于2,我們將其稱為右反轉(zhuǎn)。
如果較小的索引最多是N大于2,而較大的索引大于N超過2,則我們將其稱為拆分反轉(zhuǎn)。
我們可以用這些術語討論遞歸所取得的進展。
當我們對數(shù)組的左半部分進行遞歸時,如果我們正確地實現(xiàn)了我們的算法,那么我們將能夠成功地計算出純粹位于前半部分的所有反轉(zhuǎn)。
這些恰恰是左反轉(zhuǎn)。
同樣,在數(shù)組的右半部分([聽不清]數(shù)組的后半部分)進行第二次遞歸調(diào)用將成功計算所有正確的反轉(zhuǎn)。
仍然存在如何計算分裂倒數(shù)的問題。
但是,即使遞歸調(diào)用完成了工作,我們也不會感到驚訝。
當然,Merge Short就是這種情況,其中[聽不清]神奇地負責對數(shù)組的左半部分進行排序,對數(shù)組的右半部分進行排序。
但是,在他們返回之后,仍然存在將這兩個排序列表合并為一個的問題。
再一次,在遞歸之后將是清理并計算分割反轉(zhuǎn)的次數(shù)。
因此,例如,如果您回到我們之前研究過的六元素數(shù)組135246,您會發(fā)現(xiàn)實際上所有的反轉(zhuǎn)都是分裂的。
因此,遞歸調(diào)用都將返回零計數(shù)。
該示例的所有工作將由count split inversions子例程完成。
因此,讓我們在預想不到的情況下,對該算法的未得到充分說明的高級描述進行總結(jié)。
有一個基本案例。
為了完整起見,我將其寫下來,即如果給我們一個單元素數(shù)組,那么肯定沒有反轉(zhuǎn),因此我們可以立即將答案返回零。
對于更大的數(shù)組,我們將進行分而治之。
因此,我們將通過遞歸調(diào)用計算左反轉(zhuǎn)。
通過遞歸調(diào)用進行正確的反轉(zhuǎn)。
然后,我們將使用一些當前未實現(xiàn)的子例程來計算拆分的倒數(shù)。
由于每個反轉(zhuǎn)都是向左或向右或分裂,并且最多只能是這三個反轉(zhuǎn)之一,因此,完成這三件事之后,我們可以簡單地返回它們的總和。
這就是我們對如何計算反轉(zhuǎn)次數(shù)的高級攻擊。
當然,我們需要指定如何計算分割反轉(zhuǎn)的數(shù)量。
而且,我們?nèi)鄙僭撟永虂砜焖龠\行。
打個比方說,在遞歸調(diào)用之外,我們只做線性工作。
Outs-,在合并子例程中。
在這里,我們只想做線性工作來計算分割反演的次數(shù)。
如果我們成功實現(xiàn)了這一目標,并且我們產(chǎn)生了正確的線性限制時間來計算拆分入侵的數(shù)量,那么整個遞歸算法將以大O運行。
N的
登錄時間。
整體節(jié)奏在O中運行的原因。
N的
登錄時間與合并短時間在N中運行的原因完全相同。
登錄時間。
有兩個遞歸調(diào)用。
每個問題只有一半的大小。
在遞歸調(diào)用之外,我們將進行線性工作。
因此,您可以復制與用于合并short相同的遞歸樹參數(shù)。
在這里同樣適用。
或者,很快我們將介紹master方法,并且作為一種非常特殊的情況,它將證明該算法(如果我們可以實現(xiàn)的話)將在O中運行。
N的
登錄時間。
現(xiàn)在要實現(xiàn)的一件事是,這是一個相當雄心勃勃的目標,它可以計算線性時間中分割反轉(zhuǎn)的數(shù)量。
并不是說分裂反轉(zhuǎn)不會太多。
實際上可能有很多。
如果您有一個數(shù)組,其中數(shù)組的前半部分包含2加上1的數(shù)字N,則最多為N。
而數(shù)組的第二部分包含一個數(shù)字,最多一個大于N的兩個數(shù)字,該數(shù)字具有一個二次數(shù)的求逆,所有求逆均被拆分。
因此,我們在這里嘗試做的是僅使用線性時間來計算二次數(shù)。
真的可以做到嗎?是的,可以的,我們將在下一個視頻中看到。