-
Notifications
You must be signed in to change notification settings - Fork 93
/
BinarySearch.cpp
160 lines (134 loc) · 6.56 KB
/
BinarySearch.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// BINARY SEARCH 101 in C++ [ The only guide you will need to start with binary search ]
// DISCLAIMER: Mugging up the code won't help you in long run. To tackle tricky problems conceptual knowledge is must. Hence read the comments[concept] carefully.
#include<iostream>
using namespace std;
// Let's say we are given a sorted array of integers
// int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Why do we need Binary Search in the first place?
// Binary Search is a search algorithm that finds the position of a target value within a sorted array.
// But can't we use linear search for this?
int getTargetIndexUsingLinearSearch(int arr[],int size,int target){
for(int i=0;i<size;i++){
if(arr[i]==target){
return i;
}
}
return -1; // If target is not found
}
// Time Complexity of Linear Search is O(n) where n is the size of the array
// Linear search is not efficient for large arrays.
// Notice the inefficiency here in the above code. We are not leveraging the fact that the array is sorted.
// In sorted array we can stand at a index(say middle) and check whether our desired target lies in rightside or leftside of the middle index.
// If it lies in rightside then we can discard the leftside of the array and search in the rightside.
// If it lies in leftside then we can discard the rightside of the array and search in the leftside.
// This is the idea behind Binary Search.
// At every step we are discarding half of the array and searching in the other half.
// n -> n/2 -> n/4 -> n/8 ...... -> 1. Let k be the number of steps to go from n->1 then n/2^k = 1. So, n = 2^k. So, k = log2(n).
// the number of steps is log2(n) or more specifically log2(range)
// Enough of text, Let's visualize the algorithm now https://assets.leetcode.com/static_assets/posts/1EYkSkQaoduFBhpCVx7nyEA.gif gif credit: AminiCK
// Let's implement Binary Search in C++
int getTargetIndexUsingBinarySearch(int arr[],int size,int target) {
int low = 0, high = size-1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) // target found
return mid;
else if (arr[mid] < target) // Go right
low = mid + 1;
else if (arr[mid] > target) // Go left
high = mid - 1;
}
return -1;
};
int getTargetIndexUsingBinarySearch2(int arr[],int size,int target) {
int low=0,high=size;
while(low<high){
int mid=(low+high)>>1;
if(arr[mid]==target)return mid;
else if(arr[mid]>target){
high=mid;
}else{
low=mid+1;
}
}
return -1;
};
// We are not done yet :). The main show begins now !
/*
Notice the above 2 ways of writing binary search code. There are main 2 differences
1) Search space which is defined as [low,high] range.
In the first one search space is [0,size-1] and in the second one search space is [0,size].
In the first one search space is all the values answer can take.
In the second one search space is all the values answer can take except size, we consider size also to avoid infinite loop.
2) The way mid is calculated.
In the first one mid is calculated as low + (high - low) / 2 and in the second one mid is calculated as (low+high)>>1.
We are doing this to avoid infinte loop and overflow in case of large values of low and high.
*/
// Binary search problems can get heavily complex, and without consistent rules, it's very hard to write predictable code.
/* Problems one gets into while implementing binary search
1. Infinity loop
2. Can't decide where to shrink
3. When to exit the loop
*/
/*
Different way to calculate mid;
1. mid = (low + high) / 2;
2. mid = low + (high - low) / 2;
3. mid = low + (high - low+1) / 2 ;
4. mid = low + ((high - low) >> 1);
5. mid = (low + high) >> 1;
The disadvantage of 1 is that it may cause overflow, because (low + high) may be larger than the maximum value of int.
RED ALERT: Don't just blindly use any way to calculate mid, choose mid according to how you are writing while condition
i.e whether while(low<high) or while(low<=high);
Consider the following example:
int low=0,high=size-1;
while(low<=high){
int mid = low + ((high - low) / 2);
if (target < arr[mid]) {
hi = mid - 1
} else {
lo = mid;
}The only guide you will need to start with binary search
}
consider int arr[]={1,2} and target=3;
here low=0,high=1;
mid = low + ((high - low) / 2); => mid=1;
Now control falls into else block making low=0 again and it keeps spinning in an infinite loop.
Takeaway: Always think of a case where only 2 elements are present to check if your code falls into infinite loop or not
*/
// Now it should not take much effort to write recursive binary search code
// Recursive Binary Search C++
int getTargetIndexUsingRecursiveBinarySearch(int arr[], int low, int high, int target)
{
if (high >= low) {
int mid = low + (high - low) / 2;
// If the middle element is the target itself
if (arr[mid] == target)
return mid;
// If element is smaller than middle element, then search in left subarray
if (arr[mid] > target)
return getTargetIndexUsingRecursiveBinarySearch(arr, low, mid - 1, target);
// else search in right subarray
return getTargetIndexUsingRecursiveBinarySearch(arr, mid + 1, high, target);
}
// We reach here when element is not
// present in array
return -1;
}
// If these things are taken care of then you will float in sea of [AC]s :D
/*
General Tips:
1. Always follow one search space notation either [0,size-1] or [0,size]
2. Make sure that all possible answers are present in your search space
For example: Consider a problem where you need to find an index to insert a element in a sorted array so that after insertion the array remains sorted
In this case in the low=0,high=size-1 convention the search space now becomes low=0, high=size as the element can be inserted at the last index too
in the low=0, high=size convention the search space now becomes low=0, high=size+1.
3. Don't overflow the mid calculation
4. Avoid infinity loop by picking the correct mid and shrinking logic
5. Always think of the case when there are 2 elements left
*/
// In the end, I would say everybody has their own style of binary search, find the style that works for you!
/*
Now it would be a good idea to solve some problems using binary search https://leetcode.com/discuss/study-guide/2452472/Binary-Search-Problem-Types
*/
// HAPPY CODING... !!!