-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
233 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,6 @@ on: | |
|
||
push: | ||
|
||
pull_request: | ||
|
||
jobs: | ||
format: | ||
runs-on: ubuntu-latest | ||
|
115 changes: 115 additions & 0 deletions
115
Algorithms/Searching-Algorithms/Binary-Search/01-lower&upper-bound.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
## Find Lower and Upper bound in an array. | ||
|
||
### Lower Bound : | ||
|
||
If we have a sorted array `arr` and a target element `x` which is supposed to be found in that array, then a Lower bound is the **Smallest** `index` in that array such that, | ||
|
||
```cpp | ||
arr[index] >= x; | ||
``` | ||
|
||
--- | ||
|
||
**Example :** | ||
|
||
```cpp | ||
int arr[6] = {1, 2, 4, 4, 5, 7}; | ||
int x = 4; // element to be found in array | ||
``` | ||
If we iterate over the array, we can find that 4 >= 4, 4 >= 4, 5 >= 4 and 7 >= 4. But the first occurence of 4 at index 2 satisfies the condition as it is `>=` the target element and it's index is the smallest of all. | ||
**Hence, The Lower bound of this array is 2.** | ||
--- | ||
### Upper Bound : | ||
If we have a sorted array `arr` and a target element `x` which is supposed to be found in that array, then an Upper bound is the **Smallest** `index` in that array such that, | ||
```cpp | ||
arr[index] > x; // note the sign here | ||
``` | ||
|
||
--- | ||
|
||
**Example :** | ||
|
||
```cpp | ||
int arr[6] = {1, 2, 4, 4, 5, 7}; | ||
int x = 4; // element to be found in array | ||
``` | ||
If we iterate over the array, we can find that 5 > 4 and 7 > 4. But the value 5 at index 4 satisfies the condition as it is `>` the target element and it's index is the smallest of all. | ||
**Hence, The upper bound of this array is 4.** | ||
--- | ||
**Note :** There could be an edge case where no such target element exists or which satisfies `arr[index] >= target` or `arr[index] > target`, then we will return the nth element of the array because, then it would the hypothetical lower or upper bound for that array. | ||
**Example :** | ||
```cpp | ||
int arr[6] = {1, 2, 4, 4, 5, 7}; | ||
int x = 7; | ||
/* | ||
this x value would have upper bound == 6, | ||
as no element is > than 7 | ||
*/ | ||
``` | ||
|
||
--- | ||
|
||
**Implementation :** | ||
|
||
```cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
|
||
int lowerBound(int* arr, int n, int x){ | ||
int low = 0, high = n - 1; | ||
int ans = n; // edge case | ||
while (low <= high){ | ||
int mid = (low + (high - low)) / 2; | ||
// maybe answer | ||
if (arr[mid] >= x){ | ||
ans = mid; | ||
// look for more small index in left | ||
high = mid - 1; | ||
} else { | ||
low = mid + 1; // look for right | ||
} | ||
} | ||
return ans; | ||
} | ||
|
||
int upperBound(int* arr, int n, int x){ | ||
int low = 0, high = n - 1; | ||
int ans = n; | ||
while (low <= high){ | ||
int mid = (low + (high - low)) / 2; | ||
// maybe answer | ||
if (arr[mid] > x){ | ||
ans = mid; | ||
// look for more small index in left | ||
high = mid - 1; | ||
} else { | ||
low = mid + 1; // look for right | ||
} | ||
} | ||
return ans; | ||
} | ||
|
||
int main(){ | ||
int n; cin >> n; | ||
int arr[n]; | ||
for (int i = 0; i < n; i++>){ | ||
cin >> arr[i]; | ||
} | ||
int x; cin >> x; | ||
cout << "Lower Bound : " << lowerBound(arr, n, x); | ||
cout << "Upper Bound : " << upperBound(arr, n, x); | ||
return 0; | ||
} | ||
``` |
117 changes: 117 additions & 0 deletions
117
Algorithms/Searching-Algorithms/Binary-Search/binary-search.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# Binary Search. | ||
|
||
_Search Element in a Linear **Sorted** Data Structure._ | ||
|
||
**Time Complexity:** | ||
|
||
1. Best Case: O(1) --> Element at middle of the array. | ||
2. Average / Worst Case: O(log n) --> Element at 1st or last position. | ||
|
||
## Logic. | ||
|
||
1. Find Mid --> mid = start + (end - start) / 2. | ||
2. Compare mid with target --> possible comparisons (mid == target) or (mid > target) or (mid < target). | ||
3. If mid == target, return mid. | ||
4. If mid != target, change path w.r.t (mid > target) or (mid < target) | ||
5. If mid > target, start --> same, end --> mid - 1. | ||
6. If mid < target, end --> same, start --> mid + 1. | ||
7. Repeat. | ||
|
||
## Implementation 1 - Iterative Approach | ||
|
||
```cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
|
||
int binarySearch(int *arr, int size, int target) { | ||
int start = 0; | ||
int end = size - 1; | ||
int mid = start + (end - start) / 2; | ||
while (start <= end) | ||
{ | ||
if (arr[mid] == target) | ||
return mid; | ||
if (arr[mid] > target) | ||
end = mid - 1; | ||
else | ||
start = mid + 1; | ||
mid = start + (end - start) / 2; | ||
} | ||
return -1; | ||
} | ||
|
||
int main() { | ||
int arr[5] = {1, 2, 3, 4, 5}; | ||
int index = binarySearch(arr, 5, 3); | ||
if (index == -1) | ||
cout << "NOT FOUND!"; | ||
else | ||
cout << "Element found at Index " << index; | ||
return 0; | ||
} | ||
|
||
``` | ||
--- | ||
## Implementation 2 - Recursive Approach | ||
```cpp | ||
#include <bits/stdc++.h> | ||
using namespace std; | ||
int binarySearch(vector<int>&arr, int low, int high, int target) { | ||
// base case | ||
if (low > high) return -1; | ||
// calculate mid | ||
int mid = low + (high - low) / 2; | ||
// if found, return mid index | ||
if (arr[mid] == target) return mid; | ||
// if target > arr[mid], call the binarySearch function with updated low index. | ||
else if (target > arr[mid]) return binarySearch(arr, mid+1, high, target); | ||
// else when target < arr[mid], call the binarySearch function with updated high index. | ||
return binarySearch(arr, low, mid-1, target); | ||
} | ||
int search(vector<int>&nums, int target){ | ||
return binarySearch(nums, 0, nums.size() - 1, target); | ||
} | ||
int main() { | ||
int vector<int>arr = {1, 2, 3, 4, 5}; | ||
int index = search(arr, 5, 3); | ||
if (index == -1) | ||
cout << "NOT FOUND!"; | ||
else | ||
cout << "Element found at Index " << index; | ||
return 0; | ||
} | ||
``` | ||
|
||
## Linear Search v/s Binary Search. | ||
|
||
In Linear search, for the worst case, if the size of array is 1000, then the function will perform 1000 comparisons. | ||
In Binary Search, for worst case, for 1000 size array, the function will perform log<sub>2</sub>(1000) = 10 comparisons, | ||
which is 100 times less than Linear Search. | ||
|
||
## How O(log n) ? | ||
|
||
Suppose a N sized array perform binary search, then the middle element will be at N/2<sup>1</sup> position where 1 represents 1st comparison. | ||
|
||
The next mid will be at N/2<sup>2</sup> Position where 2 represents 2nd comparison. | ||
|
||
Similarly at last comparison, N/2<sup>k</sup> , the mid = size of array i.e, 1. | ||
|
||
Therefore N/2<sup>k</sup> = 1 | ||
|
||
N = 2<sup>k</sup> | ||
|
||
Log<sub>2</sub>N = K | ||
|
||
Which means, at kth comparison, the size of array will be log<sub>2</sub>N |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters