數組進行多少次OP操作,纔能有序

1 題目描述:

有一個數組:2,1,4,3。對於數組,有一種操作op(idx):將該index對應的數字移到首位。比如:

op(3):  2 1 43 -> 3 2 1 4

op(1):  3 2 14 -> 2 3 1 4
op(2):  2 3 1 4 -> 1 2 3 4 

問對於給定的數組,數組各個元素是任意的整數,可能有重複值,需要多少次OP操作,才能使得數組有序?

對於上面的例子,需要3次即可。

 

2. 問題解析:

最壞的情況需要 n 次就夠了,第 i 次找到數組中倒數第 i 大的數,然後進行OP操作,最後一定會使得該數組是有序的。

但是要最少幾次,如何解決?

 

2.1 時間:O(n^2)  空間:O(1)

對於 2 1 4 3,4肯定不需要OP,接下來對於3,必須要OP,變成了 3 2 1 4。如果3進行OP了,那麼其他小於3的數(1,2)都需要進行OP的,否則不能跑到 3 的前面去。

再比如 2 1 6 3 7 5 4, 發現7、6都需要OP,而從 5 開始需要進行OP了,那麼答案就是所有<=5 的數了。這種算法需要能找到 2 1 6 3 7 5 4 中 遞增序列6, 7. 複雜度是O(n^2),空間複雜度是O(1)。

 

2.2 時間:O(n) 空間:O(1)

8 6 5 7 9 5 4

目標:找到最大的數、第二大的數、第三大的數,且最大的數在最後,其他幾位數依次在前面。比如

8 6 5 7 9 5 4 ->8 6 5 7 9 5 4

5 2 1 6 3 7 0 4 ->5 2 1 6 3 7 0 4

3 4 8 10 8 -> 3 4 8 10 8 (這種情況下只能是10,因爲8出現2次,其中1次還在10後面,因此排除8)

當找到這個遞增序列後,比如:5 2 1 6 3 7 0 4->5 2 1 6 3 7 0 4。 那麼我知道4一定在5之後出現了,那麼4一定要進行op操作,放到首位,只要4放到了首位,那麼其他的3,2,1,0等<=4的數,全都是要進行操作的。(3也要放到首位,那麼2也要放到首位,那麼...)。可以看到只有 5, 6, 7三個數不需要進行op操作。因此總的op數量是n-3 = 8 - 3 = 5.



爲了找到這個序列,我打算:從右往左遍歷,

idx: 爲遍歷的指針;p: 上述遞增序列的最低位指針, _min: 記錄arr[idx, p-1]之間的最大的值。在遍歷過程中,不斷地把遞增序列移到右側,比如

idx: 6, p: 6,

8 6 5 7 9 5 4

_min: uninitialzed



idx: 5, p: 6,

8 6 5 7 9 5 4 [ 5比4大,因此交換 5和4的位置 ]

8 6 5 7 9 4 5

_min: 4 (_min更新爲4)

 

idx: 4, p: 6

8 6 5 7 9 4 5  [ 9比5大,因此交換 9 和 5 的位置 ]

8 6 5 7 5 4 9

_min: 5 (更新爲5和4中的最大者)



idx: 3, p: 6

8 6 5 7 5 4 9  

8 6 5 4 5 7 9  [ 7 比 9 小,因此7可以納入遞增序列中: 交換4和7,p-- ]

_min: 5 (4,5中的最大者)



idx: 2, p: 5

8 6 5 4 5 7 9  [ 由於5 <= _min(5), 因此直接 idx--]

 

 

idx:1 , p: 5

8 6 5 4 5 7 9  [ 6大於_min,因此是ok,更新遞增序列, swap(6, 5), p--]

8 5 5 4 6 7 9  [swap之後的結果]



idx: 0, p: 4

8 5 5 4 6 7 9 [ 8比_min大,8比6都大,因此p不斷自增,知道8 < 9才停止,此時p指向了9,如下圖]

8 5 5 4 6 7 9 [ 8 比 9 小,因此swap(8, 7)]

7 5 5 4 6 8 9 [結果]



idx: -1, p: 5

-> break;

因此最大遞增序列是長度爲2,{8, 9}。因此返回 n- 2 即 7 - 2 = 5



複雜度分析:

掃描的時間爲 O(n)。對於swap操作,最後的遞增序列類似於一個棧,每個元素最多進棧出棧一次,也是最多 O(n)。 因此時間複雜度是 O(n),空間複雜度是 O(1)。


3, 更優算法

這種算法的時間複雜度是 O(n),空間複雜度是 O(1)。

具體思路:8 6 5 7 10 9 4。從左往右找到階段性的山腰(8,10),然後把之間的山谷和山背都去掉(6,5,7, 以及 9,4)

有p1, p2兩個指針,p1指向8,p2指向6,比8小,然後右移。指向5,還是小於8,接着右移。最後指向了10,此時 p1也更新指向到10. 片

繼續從9開始走。

p1指向過(8,10),p2指向過(6,5,7,9,4)p2中最大的是9,因此需要把 p1 指向過的(8,10)中比9小的排除掉就是最後的答案。排除的過程就是:p1,p2 再重複上面的過程,只是現在需要記錄 p1 所指向的元素中比 9大的數量是多少,這就是最後的答案。

上面這種方法,寫代碼簡單,可行。時間空間複雜度也是可以的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章