|
1 | 1 | # Binary Search
|
2 | 2 |
|
| 3 | +## Background |
| 4 | + |
3 | 5 | Binary search is a search algorithm that finds the position of a target value within a sorted array or list. It compares
|
4 | 6 | the target value to the middle element of the search range, then, based on the comparison, narrows the search to the
|
5 | 7 | upper or lower half of the current search range.
|
6 | 8 |
|
7 |
| -Two versions of binary search has been implemented in this repository - BinarySearch and BinarySearchTemplated. |
8 |
| - |
9 |
| -## BinarySearch |
10 |
| - |
11 |
| - |
12 |
| -Image Source: GeeksforGeeks |
13 |
| - |
14 |
| -BinarySearch is a more straightforward and intuitive version of the binary search algorithm. In this approach, after the |
15 |
| -mid-value is calculated, the high or low pointer is adjusted by just one unit. From the above example, after mid points |
16 |
| -to index 4 in the first search, the low pointer moves to index 5 (+1 from 4) when narrowing the search. Similarly, when |
17 |
| -mid points to index 7 in the second search, the high pointer shifts to index 6 (-1 from 7) when narrowing the search. |
18 |
| -This prevents any possibility of infinite loops. During the search, the moment mid-value is equal to the target value, |
19 |
| -the search ends prematurely. Note that there is no need for a "condition" method as the condition is already captured |
20 |
| -in the predicates of the if-else blocks. |
21 |
| - |
22 |
| -## BinarySearchTemplated |
23 |
| - |
24 |
| -BinarySearchTemplated removes the condition that checks if the current mid-value is equal to the target (which helps to |
25 |
| -end the search the moment the target is found). The template adds a "condition" method which will be modified based on |
26 |
| -the requirements of the implementation. |
27 |
| - |
28 |
| -The narrowing of the search space differs from BinarySearch - only the high pointer will be adjusted by one unit. |
29 |
| - |
30 |
| -This template will work for most binary search problems and will only require the following changes: |
31 |
| - |
32 |
| -- Search space (high and low) |
33 |
| -- Condition method |
34 |
| -- Returned value (low or low - 1) |
35 |
| - |
36 |
| -### Search Space (Requires change) |
37 |
| - |
38 |
| -Simply modify the initialisation of the high and low pointer according to the [search space](#search-space-adjustment). |
39 |
| - |
40 |
| -### Condition (Requires change) |
41 |
| - |
42 |
| -We assume that when the condition returns true, the current value "passes" and when the condition returns false, the |
43 |
| -current value "fails". |
44 |
| - |
45 |
| -Note that in this template, the conditional blocks |
46 |
| - |
47 |
| -``` |
48 |
| -if (condition(x)) { |
49 |
| - high = mid; |
50 |
| -} else { |
51 |
| - low = mid + 1; |
52 |
| -} |
53 |
| -``` |
54 |
| - |
55 |
| -requires elements that "fail" the condition to be on the left of the elements that "pass" the condition, see below, in a |
56 |
| -sorted array due to the way the high and low pointers are reassigned. |
57 |
| - |
58 |
| - |
59 |
| - |
60 |
| -Hence, we will need to implement a condition method that is able to discern between arrays that "pass" and "fail" |
61 |
| -accurately and also place them in the correct relative positions i.e. "fail" on the left of "pass". Suppose we change |
62 |
| -the condition method implementation in BinarySearchTemplated from `value >= target` to `value <= target`, what will |
63 |
| -happen? |
64 |
| -<details> |
65 |
| -<summary> <b>what will happen?</b> </summary> |
66 |
| -The array becomes "P P F F F F" and the low and high pointers are now reassigned wrongly. |
67 |
| -</details> |
68 |
| - |
69 |
| -### Returned Value (Requires change) |
70 |
| - |
71 |
| -In this implementation of BinarySearchTemplated, we return the first "pass" in the array with `return low`. This is |
72 |
| -because our condition method implementation encompasses the target value that we are finding i.e. when |
73 |
| -`value == target`. |
74 |
| - |
75 |
| -```java |
76 |
| -public static boolean condition(int value, int target) { |
77 |
| - return value >= target; |
78 |
| -} |
79 |
| -``` |
80 |
| - |
81 |
| - |
82 |
| - |
83 |
| -However, if we want to return the last "fail" in the array, we will `return low - 1`. |
84 |
| - |
85 |
| -Suppose now we modify the condition to be `value > target`, how can we modify our BinarySearchTemplated to still work as |
86 |
| -expected? |
87 |
| -<details> |
88 |
| -<summary> <b>value > target?</b> </summary> |
89 |
| -Replace `return low` with `return low - 1` and replace arr[low] with arr[low - 1] as now the target value is the last |
90 |
| -"fail". |
91 |
| -</details> |
92 |
| - |
93 |
| -### Search Space Adjustment |
94 |
| - |
95 |
| -What should be the search space adjustment? Why is only low reassigned with an increment and not high? |
96 |
| - |
97 |
| -Due to the nature of floor division in Java's \ operator, if there are two mid-values within the search range, which is |
98 |
| -when the number of elements is even, the first mid-value will be selected. Suppose we do not increment the low pointer |
99 |
| -during reassignment, `low = mid`, let us take a look at the following example: |
100 |
| - |
101 |
| - |
102 |
| - |
103 |
| -The search space has been narrowed down to the range of index 1 (low) to 2 (high). The mid-value is calculated, |
104 |
| -`mid = (1 + 2) / 2`, to be 1 due to floor division. Since `2 < 5`, we enter the else block where there is reassignment |
105 |
| -of `low = mid`. This means that the low pointer is still pointing to index 1 and the high pointer remains unchanged at |
106 |
| -index 2. This results in an infinite loop as the search range is not narrowed down. |
107 |
| - |
108 |
| -To resolve this issue, we need `low = mid + 1`, which will result in the low pointer pointing to index 2 in this |
109 |
| -scenario. We still ensure correctness because the mid-value is not the target value, as the mid-value < target, and we |
110 |
| -can safely exclude it from the search range. |
111 |
| - |
112 |
| -Why do we not need to increment the high pointer during reassignment? This is because the mid-value could be the target |
113 |
| -as the condition implemented is `value >= target`, hence, we cannot exclude it from the search range. |
114 |
| - |
115 |
| -See [here](./binarySearchTemplatedExamples/README.md) to use the template for other problems |
116 |
| - |
117 |
| -Credits: [Powerful Ultimate Binary Search Template](https://leetcode.com/discuss/general-discussion/786126/python-powerful-ultimate-binary-search-template-solved-many-problems) |
118 |
| - |
119 |
| -## Complexity Analysis |
| 9 | +## Implementation Invariant |
120 | 10 |
|
121 |
| -**Time**: |
| 11 | +At the end of each iteration, the target value is either within the search range or does not exist in the search space. |
122 | 12 |
|
123 |
| -- Worst case: O(log n) |
124 |
| -- Average case: O(log n) |
125 |
| -- Best case: |
126 |
| - - BinarySearch O(1) |
127 |
| - - BinarySearchTemplated O(log n) |
| 13 | +## BinarySearch and BinarySearchTemplate |
128 | 14 |
|
129 |
| -BinarySearch: |
130 |
| -In the worst case, the target is either in the first index or does not exist in the array at all. |
131 |
| -In the best case, the target is the middle (odd number of element) or the first middle element (even number of elements) |
132 |
| -if floor division is used to determine the middle. |
| 15 | +We will discuss more implementation-specific details and complexity analysis in the respective folders. In short, |
| 16 | +1. The [binarySearch](binarySearch) method is a more straightforward and intuitive version of the binary search |
| 17 | +algorithm. |
| 18 | +2. The [binarySearchTemplate](binarySearchTemplated) method provides a more generalised template that can be used for |
| 19 | +most binary search problems by introducing a condition method that can be modified based on the requirements of the |
| 20 | +implementation. |
133 | 21 |
|
134 |
| -BinaryTemplated: |
135 |
| -In all cases, O(log n) iterations will be required as there is no condition to exit the loop prematurely. |
136 | 22 |
|
137 |
| -**Space**: O(1) since no new data structures are used and searching is only done within the array given |
0 commit comments