@@ -10,52 +10,100 @@ Two versions of binary search has been implemented in this repository - BinarySe
10
10
Image Source: GeeksforGeeks
11
11
12
12
BinarySearch is a more straightforward and intuitive version of the binary search algorithm. In this approach, after the
13
- mid-value is calculated, the high and low pointers are adjusted by just one unit. From the above example, after mid
14
- points to index 4 in the first search, the low pointer moves to index 5 (+1) when narrowing the search. Similarly, when
15
- mid points to index 7 in the second search, the high pointer shifts to index 6 (-1) when narrowing the search. This
16
- prevents any possibility of infinite loops.
13
+ mid-value is calculated, the high or low pointer is adjusted by just one unit. From the above example, after mid points
14
+ to index 4 in the first search, the low pointer moves to index 5 (+1 from 4) when narrowing the search. Similarly, when
15
+ mid points to index 7 in the second search, the high pointer shifts to index 6 (-1 from 7) when narrowing the search.
16
+ This prevents any possibility of infinite loops. During the search, the moment mid-value is equal to the target value,
17
+ the search ends prematurely. Note that there is no need for a "condition" method as the condition is already captured
18
+ in the predicates of the if-else blocks.
17
19
18
20
## BinarySearchTemplated
19
21
20
22
BinarySearchTemplated removes the condition that checks if the current mid-value is equal to the target (which helps to
21
23
end the search the moment the target is found). The template adds a "condition" method which will be modified based on
22
24
the requirements of the implementation.
23
25
24
- The narrowing of the search space differs from BinarySearch - only one of the high or low pointers will be adjusted by
25
- one unit.
26
+ The narrowing of the search space differs from BinarySearch - only the high pointer will be adjusted by one unit.
26
27
27
28
This template will work for most binary search problems and will only require the following changes:
28
29
- Search space (high and low)
29
30
- Condition method
30
31
- Returned value (low or low - 1)
31
32
32
33
### Search Space (Requires change)
33
- Simply modify the initialisation of the high and low pointer according to the search space.
34
+ Simply modify the initialisation of the high and low pointer according to the [ search space] ( #search-space-adjustment ) .
34
35
35
36
### Condition (Requires change)
36
37
We assume that when the condition returns true, the current value "passes" and when the condition returns false, the
37
38
current value "fails".
38
39
39
- In this template, we want to find the first "pass" in the array.
40
-
41
- INSERT IMAGE OF FIRST PASS
40
+ Note that in this template, the conditional blocks
41
+ ```
42
+ if (condition(x)) {
43
+ high = mid;
44
+ } else {
45
+ low = mid + 1;
46
+ }
47
+ ```
48
+ requires elements that "fail" the condition to be on the left of the elements that "pass" the condition, see below, in a
49
+ sorted array due to the way the high and low pointers are reassigned.
50
+
51
+ ![ binary search templated 1 img] ( ../../../../../docs/assets/images/BinarySearchTemplated1.jpeg )
52
+
53
+ Hence, we will need to implement a condition method that is able to discern between arrays that "pass" and "fail"
54
+ accurately and also place them in the correct relative positions i.e. "fail" on the left of "pass". Suppose we change
55
+ the condition method implementation in BinarySearchTemplated from ` value >= target ` to ` value <= target ` , what will
56
+ happen?
57
+ <details >
58
+ <summary > <b >what will happen?</b > </summary >
59
+ The array becomes "P P F F F F" and the low and high pointers are now reassigned wrongly.
60
+ </details >
42
61
43
62
### Returned Value (Requires change)
44
- In the implementation of BinarySearchTemplated, return low was used to find the first "pass".
63
+ In this implementation of BinarySearchTemplated, we return the first "pass" in the array with ` return low ` . This is
64
+ because our condition method implementation encompasses the target value that we are finding i.e. when
65
+ ` value == target ` .
66
+
67
+ ``` java
68
+ public static boolean condition(int value, int target) {
69
+ return value >= target;
70
+ }
71
+ ```
72
+ ![ binary search templated 1 img] ( ../../../../../docs/assets/images/BinarySearchTemplated2.jpeg )
73
+
74
+ However, if we want to return the last "fail" in the array, we will ` return low - 1 ` .
75
+
76
+ Suppose now we modify the condition to be ` value > target ` , how can we modify our BinarySearchTemplated to still work as
77
+ expected?
78
+ <details >
79
+ <summary > <b >value > target?</b > </summary >
80
+ Replace ` return low ` with ` return low - 1 ` and replace arr[ low] with arr[ low - 1] as now the target value is the last
81
+ "fail".
82
+ </details >
45
83
46
- EXPLANATION TBC, STILL THINKING HOW TO PHRASE IT.
47
84
48
85
### Search Space Adjustment
49
- What should be the search space adjustment? (Why only low = mid + 1)
86
+ What should be the search space adjustment? Why is only low reassigned with an increment and not high?
87
+
88
+ Due to the nature of floor division in Java's \ operator, if there are two mid-values within the search range, which is
89
+ when the number of elements is even, the first mid-value will be selected. Suppose we do not increment the low pointer
90
+ during reassignment, ` low = mid ` , let us take a look at the following example:
91
+
92
+ ![ binary search templated 1 img] ( ../../../../../docs/assets/images/BinarySearchTemplated3.jpeg )
93
+
94
+ The search space has been narrowed down to the range of index 1 (low) to 2 (high). The mid-value is calculated,
95
+ ` mid = (1 + 2) / 2 ` , to be 1 due to floor division. Since ` 2 < 5 ` , we enter the else block where there is reassignment
96
+ of ` low = mid ` . This means that the low pointer is still pointing to index 1 and the high pointer remains unchanged at
97
+ index 2. This results in an infinite loop as the search range is not narrowed down.
50
98
51
- Due to the nature of floor division in Java's \ operator, the searched mid-index will always be smaller than the high
52
- pointer of the previous search range. On the other hand, low = mid + 1, ensures that the searched mid-index is always
53
- larger than the low pointer of the previous search range. This ensures that the search range is narrowed in every loop
54
- and prevents the possibility of infinite loops.
99
+ To resolve this issue, we need ` low = mid + 1 ` , which will result in the low pointer pointing to index 2 in this
100
+ scenario. We still ensure correctness because the mid-value is not the target value, as the mid-value < target, and we
101
+ can safely exclude it from the search range.
55
102
56
- INSERT IMAGE HERE TO EXPLAIN
103
+ Why do we not need to increment the high pointer during reassignment? This is because the mid-value could be the target
104
+ as the condition implemented is ` value >= target ` , hence, we cannot exclude it from the search range.
57
105
58
- As we close in towards the target value, the final low = mid + 1 narrows the search range from low. TBC ON EXPLANATION
106
+ See [ here ] ( ./binarySearchTemplatedExamples/README.md ) to use the template for other problems
59
107
60
108
Credits: [ Powerful Ultimate Binary Search Template] ( https://leetcode.com/discuss/general-discussion/786126/python-powerful-ultimate-binary-search-template-solved-many-problems )
61
109
0 commit comments