|
给定一个只包含零、一和二的数组。根据函数编写函数O(n)对给定数组进行时间复杂序。/ ]$ ]; n t* ~* g3 w/ M- P/ F9 A
Input :Output :[0,0,1,1,1,2,2,2,2][0,0,1,1,1,2,2,2,2]
" B ~+ ~, E; X 解决方案:
4 t9 J2 v0 D8 W$ X @. ~ 方法 – I :! ]/ u& h+ o& j- Y' W1 p4 Y
解决这个问题的一个非常基本的方法是保持给定数组中零、一和二的数量,然后根据每个数字的频率操作给定数组。这种方法有点受到计数排序的启发。无论具体索引的初始值是什么,我们首先从索引零开始放置数组中的所有零,然后放置所有 1,然后放置所有 2。
+ E% R! j |5 {/ [3 |步骤:
/ M* M7 v3 ]3 H+ ]1 f+ R" h1.) 遍历给定数组一次,并不断增加遇到的数字计数。
9 o I% r' S O- w4 }9 ]0 _8 {8 Q2.) 现在从索引零开始再次遍历数组,并不断改变索引上当前元素的值,首先耗尽所有零,然后是 1,最后是 2。
G8 W. ^1 V6 \4 p. q# X1 g3 t+ Y这样,我们就有了一个排序数组,所有的零都在开始,然后是所有的 1,然后在最后一节,我们的时间复杂度是. O(n)7 G. N! m4 h0 e4 t' G3 y- N$ m
但这种方法的主要缺点是,我们必须给定数组两次来计算零、一和二的数量,第二次给定数组排序,这只能在一次通过中完成。' g/ G; j. k0 k1 X. n; a: U/ b
package Arrays; public class sort012 { public static void main(String[] args) int[]a = sort(a); for(int val : a) System.out.println(val " "); *Function to sort the given array*/ public static void sort(int[]a) /* array to keep the count of 0s,1s,2s*/ int[]freq = new int[3]* traverse the given array for filling the * frequency array*/ for(int val : a) freq[val] *pointer to traverse the given array again*/ int pointer = for(int i=0;i0) *at the current pointer plot the current number* a[pointer]=i; *increment the pointer* pointer 方法 – II :4 `4 v( b1 r2 |3 m( E
这种算法被称为Dutch national flag algorithm 或 Three way partitioning类似类型的元素分组在一起,它们的集合组也按正确的顺序排序。$ N4 K$ G& ?/ G% r# ~2 B4 M% m
现在我们有三种元素要排序。因此,我们将给定的数组分为四个部分,其中 3 被指定为zeroes,Ones和twos有一部分是unknown或者留下要探索的部分。现在,为了遍历这些部分,我们还需要 3 指针,它们实际上将给定的数组分为四段。
1 v. m9 D' U" Z# W* x8 d" o让我们把这些指针命名为低、中和高。
' l" T$ n" @. R e" M7 r现在我们可以区分这些段落的起点和终点。" z! `4 h( I: w, q
Segment-1 : zeroes: b9 b$ p5 ] U6 s+ x
这将是已知的一部分,只是zeroes包含范围为[0,low-1].- A, c! E! s; g; m3 n. A7 G
Segment-2: Ones
( S. j1 a7 I4 i' L `这也是一个知识部分,只包括 的范围[low,mid-1]。2 c7 X/ _) r6 w0 N
Segment-3 : Unexplored( W1 `- G6 A. G% h& Q$ j/ x. w
这将是一个未知的部分,因为这部分的元素还有待探索,所以它可以包含所有类型的元素,即零、一和二。这一段的范围将是[mid,high]6 \' Z% D% F, f+ `6 q/ |
Segment-4:Twos
1 b( p1 v5 `0 m这将是最后一个已知区,只包括范围[high 1,N]N 是给定数组长度或基本给定数组最后一个有效索引的二进制数。
5 ]. n# s# a" z7 j5 L该算法用于在单次传输中对给定数组进行排序:) m: [" B, D" f, O c3 k% ^
(I)初始化低,中,高指针,low = 0,mid = 0,high = N9 D& t- T+ t6 O- w4 z
(II)现在,运行一个循环并执行以下操作,直到mid最终满足指针highpointer.As的mid指针向前移动,我们一直在向前移动元素mid该指针通过将该元素与指针相应部位的元素交换到指针的正确位置。
# X1 d) N1 }2 W1 S Z g" |* |9 a(ⅲ)CASE - I:若在所述元素中mid,也就是A[mid] ==该装置的正确位置在上述范围内[0,low-因此,我们交换A[mid]与A[low] 和增量低确保元件与指数大于低较小是零。
$ k! p% i5 P3 q(iv) CASE – II:如果元素在mid,即,A[mid]==2.本手段该元件的正确位置在上述范围内[hi 1,N],所以,我们交换A[mid]与A[hi]确保指数大于高元件的递减高是两个决定。
+ d4 S! \; |+ o4 o1 J E(v) CASE – III :如果元素在中间,即A[mid]=1.这意味着元素已经在正确的部分,因为它[low,mid-1]是它需要的范围。因此,我们什么都不做,只是简单地添加中间指针。
4 n. K6 ]% Y5 @: `! l0 ?1 Q因此,总共有三种情况,让我们花点时间强调一个事实,即中指针只是元素A[mid] == 1.
6 O5 z. a4 q% H3 w: }让我们单独讨论每个案例,
8 y0 ^: d# F) J7 q6 h Q% W, p9 W7 x对于情况-我 :在这种情况下,我们增加了mid而且随着增量low指针,因为我们相信在交换之前,只有一个低指针元素可以被交换,因为当时有两个元素high指针,当mid中指针离开它的唯一原因是指针探索它。2 `5 ?: l3 X9 W$ j9 f, K- Y
对于情况- II:现在,在这种情况下,我们交换位置元素mid和high,但与案例-在这种情况下,我们不知道它会在元素中mid指数交换元素后high索引之前的交换可以是任何零,一两个,所以我们需要探索这换的元素,所以mid在这种情况下,我们不添加指针。8 y$ h7 k. n# U) x [
对于情况 – III:mid在这种情况下,正如我们已经讨论过的,因为我们知道元素 atmid是 1,所以我们必须在这里增加 mid。6 e/ r& r# O+ q' v% F4 N% ?: W
该算法的时间复杂性也是如此O(n),但它只需要一次遍历就可以对数组进行排序,与以前的方法不同,没有额外的空间。
& }6 Y7 U) U( {! A9 Z package Arrays; public class sort012 { public static void main(String[] args) int[]a = sort(a); for(int val : a) System.out.print(val " "); public static void sort(int[]a) /* Three pointers to divide the array in designated segments * as discussed in the post*/ int low=0,mid=0,high=a.length-1. while(mid这是关于对 0、1 的数组进行排序。 |
|