1
+ from typing import List , Any , Tuple
2
+ import random
3
+
4
+ # These constants stores the relative order of the 3 'colors' 0, 1 and 2.
5
+ # They can be changed as per the requirement of the user.
6
+ # The colors need not be represented by integers, they can also be other comparable or incomparable objects.
7
+ RED = 0 # In this case this is the first color of the flag.
8
+ WHITE = 1 # This is the second color of the flag.
9
+ BLUE = 2 # This is the third color of the flag.
10
+ COLORS = (RED , WHITE , BLUE )
11
+ """
12
+ The Dutch-National-Flag problem is a problem designed by Edsger Dijkstra. This is called so because the flag of Netherlands
13
+ or Dutch flag is composed of three colors and the sequence of numbers it seeks to sort is composed of 3 unique repeated values.
14
+ These values can be in any order (0,1,2) in our examples but can be made to be anything by assigning the value to RED, WHITE and BLUE
15
+ in that order.
16
+
17
+ The objective is to sort these n numbers composed of 3 unique repeated values in the most optimal way, that is O(n) (better than the normal
18
+ list.sort() method in Python which has the complexity of O(n)). Another way to solve it is by using Counting Sort but that requires 2
19
+ passes and depending on the size of array could be much more expensive than DNF algorithm (twice as much).
20
+
21
+ The idea is to maintain 4 regions inside of the sequence provided (marked by l, mid and r index).
22
+ for a sequence of size n:
23
+ Region 1 : sequence[0...l-1] should be colored RED
24
+ Region 2 : sequence[l...mid-1] should be colored WHITE
25
+ Region 3 : sequence[mid...r] is an unknown color that we must process
26
+ Region 4 : sequence[r...n] should be colored BLUE
27
+
28
+ More can be read here : https://en.wikipedia.org/wiki/Dutch_national_flag_problem
29
+
30
+ """
31
+ def dutch_national_flag (sequence : List , colors :Tuple [Any ]= COLORS ) -> None :
32
+ """
33
+ This method sorts the sequence of 3 colors given in the order in COLORS constant tuple. This method assumes (0<1<2)
34
+ but the order can be anything.
35
+ Inputs :
36
+ colors : Tuple[Any] -> a relative ordered tuple of objects that correspond to RED, WHITE and BLUE colors of the flag (in that order).
37
+ sequence : List[any] -> a sequence of length n with values a[0], a[1], a[2] ... a[n-2], a[n-1] where a[i] in COLORS
38
+ input example : [0, 0, 2, 2, 2, 1, 1, 2, 2, 1]
39
+ output example : [0, 0, 1, 1, 1, 2, 2, 2, 2, 2]
40
+ Sorts the array in place in a single pass. O(n) time complexity and O(1) space complexity
41
+ >>> from collections import Counter
42
+ >>> arr1 = [random.choice(COLORS) for _ in range(100)]
43
+ >>> arr2 = arr1.copy()
44
+ >>> counter = Counter(arr1)
45
+ >>> arr1 = [COLORS[0] for _ in range(counter[COLORS[0]])]+[COLORS[1] for _ in range(counter[COLORS[1]])]+\
46
+ [COLORS[2] for _ in range(counter[COLORS[2]])]
47
+ >>> dutch_national_flag(arr2)
48
+ >>> arr1 == arr2
49
+ True
50
+ """
51
+ COLORS = colors
52
+ if sequence is None : return
53
+ if len (sequence ) <= 1 : return
54
+ l = 0
55
+ mid = 0
56
+ r = len (sequence )- 1
57
+ while mid <= r :
58
+ if sequence [mid ] == COLORS [0 ]:
59
+ sequence [l ], sequence [mid ] = sequence [mid ], sequence [l ]
60
+ l += 1
61
+ mid += 1
62
+ continue
63
+
64
+ if sequence [mid ] == COLORS [1 ]:
65
+ mid += 1
66
+ continue
67
+
68
+ if sequence [mid ] == COLORS [2 ]:
69
+ sequence [r ], sequence [mid ] = sequence [mid ], sequence [r ]
70
+ r -= 1
71
+ continue
72
+
73
+ raise ValueError (f"Invalid value { sequence [mid ]} inside of sequence. The elements inside the sequence must \
74
+ be in { COLORS } tuple." )
75
+
76
+ return
77
+
78
+
79
+ def main ()-> None :
80
+ """
81
+ Main method to run doctests
82
+ >>> pass
83
+ """
84
+ import doctest
85
+ doctest .testmod ()
86
+
87
+
88
+ if __name__ == "__main__" :
89
+ main ()
0 commit comments