|
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