Skip to content

Commit 10fd936

Browse files
committed
mock 1 done!
1 parent a036b2d commit 10fd936

File tree

2 files changed

+436
-8
lines changed

2 files changed

+436
-8
lines changed

Mock Interviews/Large Search Engine Company /Search Engine Company - Interview Problems - SOLUTIONS/.ipynb_checkpoints/On-Site Question 4 - SOLUTION-checkpoint.ipynb

Lines changed: 218 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,236 @@
77
"# On-Site Question 4 - SOLUTION\n",
88
"\n",
99
"## Question\n",
10-
"**You are given a list which contains integers from 1 to n, but it has a length of n+1, meaning there is a duplicate in the list. Find the duplicate integer**\n",
10+
"**Find the squareroot of a given number rounded down to the nearest integer, without using the sqrt function. For example, squareroot of a number between [9, 15] should return 3, and [16, 24] should be 4.**\n",
1111
"\n",
1212
"## Requirements\n",
1313
"\n",
14-
"** You must only use O(1) space in your solution, you can use O(n) time **\n",
1514
"** Feel free to code this out (but its recommended that you use paper/pencil or whiteboard)**"
1615
]
1716
},
17+
{
18+
"cell_type": "markdown",
19+
"metadata": {
20+
"collapsed": true
21+
},
22+
"source": [
23+
"## Solution\n",
24+
"\n",
25+
"The squareroot of a (non-negative) number N always lies between 0 and N/2. The straightforward way to solve this problem would be to check every number k between 0 and N/2, until the square of k becomes greater than or rqual to N. If k^2 becomes equal to N, then we return k. Otherwise, we return k-1 because we're rounding down. Here's the code:"
26+
]
27+
},
28+
{
29+
"cell_type": "code",
30+
"execution_count": 1,
31+
"metadata": {
32+
"collapsed": true
33+
},
34+
"outputs": [],
35+
"source": [
36+
"def solution(num): \n",
37+
" if num<0: \n",
38+
" raise ValueError \n",
39+
" if num==1: \n",
40+
" return 1 \n",
41+
" for k in range(1+(num/2)): \n",
42+
" if k**2==num: \n",
43+
" return k \n",
44+
" elif k**2>num: \n",
45+
" return k-1 \n",
46+
" return k "
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": 2,
52+
"metadata": {
53+
"collapsed": false
54+
},
55+
"outputs": [
56+
{
57+
"data": {
58+
"text/plain": [
59+
"3"
60+
]
61+
},
62+
"execution_count": 2,
63+
"metadata": {},
64+
"output_type": "execute_result"
65+
}
66+
],
67+
"source": [
68+
"solution(14)"
69+
]
70+
},
71+
{
72+
"cell_type": "code",
73+
"execution_count": 3,
74+
"metadata": {
75+
"collapsed": false
76+
},
77+
"outputs": [
78+
{
79+
"data": {
80+
"text/plain": [
81+
"3"
82+
]
83+
},
84+
"execution_count": 3,
85+
"metadata": {},
86+
"output_type": "execute_result"
87+
}
88+
],
89+
"source": [
90+
"solution(15)"
91+
]
92+
},
93+
{
94+
"cell_type": "code",
95+
"execution_count": 4,
96+
"metadata": {
97+
"collapsed": false
98+
},
99+
"outputs": [
100+
{
101+
"data": {
102+
"text/plain": [
103+
"4"
104+
]
105+
},
106+
"execution_count": 4,
107+
"metadata": {},
108+
"output_type": "execute_result"
109+
}
110+
],
111+
"source": [
112+
"solution(16)"
113+
]
114+
},
115+
{
116+
"cell_type": "markdown",
117+
"metadata": {},
118+
"source": [
119+
"The complexity of this approach is O(N), because we have to check N/2 numbers in the worst case. This linear algorithm is pretty inefficient, we can use some sort of binary search to speed it up. We know that the result is between 0 and N/2, so we can first try N/4 to see whether its square is less than, greater than, or equal to N. If it’s equal then we simply return that value. If it’s less, then we continue our search between N/4 and N/2. Otherwise if it’s greater, then we search between 0 and N/4. In both cases we reduce the potential range by half and continue, this is the logic of binary search. We’re not performing regular binary search though, it’s modified. We want to ensure that we stop at a number k, where k^2<=N but (k+1)^2>N. For example:"
120+
]
121+
},
18122
{
19123
"cell_type": "code",
20-
"execution_count": null,
124+
"execution_count": 5,
21125
"metadata": {
22126
"collapsed": true
23127
},
24128
"outputs": [],
25-
"source": []
129+
"source": [
130+
"def better_solution(num): \n",
131+
" if num<0: \n",
132+
" raise ValueError \n",
133+
" if num==1: \n",
134+
" return 1 \n",
135+
" low=0 \n",
136+
" high=1+(num/2) \n",
137+
" \n",
138+
" while low+1<high: \n",
139+
" mid=low+(high-low)/2 \n",
140+
" square=mid**2 \n",
141+
" if square==num: \n",
142+
" return mid \n",
143+
" elif square<num: \n",
144+
" low=mid \n",
145+
" else: high=mid \n",
146+
" \n",
147+
" return low"
148+
]
149+
},
150+
{
151+
"cell_type": "code",
152+
"execution_count": 9,
153+
"metadata": {
154+
"collapsed": false
155+
},
156+
"outputs": [
157+
{
158+
"data": {
159+
"text/plain": [
160+
"3"
161+
]
162+
},
163+
"execution_count": 9,
164+
"metadata": {},
165+
"output_type": "execute_result"
166+
}
167+
],
168+
"source": [
169+
"better_solution(14)"
170+
]
171+
},
172+
{
173+
"cell_type": "code",
174+
"execution_count": 10,
175+
"metadata": {
176+
"collapsed": false
177+
},
178+
"outputs": [
179+
{
180+
"data": {
181+
"text/plain": [
182+
"3"
183+
]
184+
},
185+
"execution_count": 10,
186+
"metadata": {},
187+
"output_type": "execute_result"
188+
}
189+
],
190+
"source": [
191+
"better_solution(15)"
192+
]
193+
},
194+
{
195+
"cell_type": "code",
196+
"execution_count": 11,
197+
"metadata": {
198+
"collapsed": false
199+
},
200+
"outputs": [
201+
{
202+
"data": {
203+
"text/plain": [
204+
"4"
205+
]
206+
},
207+
"execution_count": 11,
208+
"metadata": {},
209+
"output_type": "execute_result"
210+
}
211+
],
212+
"source": [
213+
"better_solution(16)"
214+
]
215+
},
216+
{
217+
"cell_type": "markdown",
218+
"metadata": {},
219+
"source": [
220+
"One difference from regular binary search is the condition of the while loop, it’s low+1<high instead of low<high. Also we have low=mid instead of low=mid+1, and high=mid instead of high=mid-1. These are the modifications we make to standard binary search. The complexity is still the same though, it’s logarithmic O(logN). Which is much better than the naive linear solution.\n",
221+
"\n",
222+
"There’s also a constant time O(1) solution which involves a clever math trick. Here it is:\n",
223+
"\n",
224+
"# $$ \\sqrt{N} = N^{0.5} = 2^{\\log_2 N^{0.5}} = 2^{0.5 \\log_2 N} $$"
225+
]
226+
},
227+
{
228+
"cell_type": "markdown",
229+
"metadata": {},
230+
"source": [
231+
"This solution exploits the property that if we take the exponent of the log of a number, the result doesn’t change, it’s still the number itself. So we can first calculate the log of a number, multiply with 0.5, take the exponent, and finally take the floor of that value to round it down. This way we can avoid using the sqrt function by using the log function. Logarithm of a number rounded down to the nearest integer can be calculated in constant time, by looking at the position of the leftmost 1 in the binary representation of the number. For example, the number 6 in binary is 110, and the leftmost 1 is at position 2 (starting from right counting from 0). So the logarithm of 6 rounded down is 2. This solution doesn’t always give the same result as above algorithms though, because of the rounding effects. And depending on the interviewer’s perspective this approach can be regarded as either very elegant and clever, or tricky and invalid. Either way, you should let your interviewer know that you are capable of the shortcut!"
232+
]
233+
},
234+
{
235+
"cell_type": "markdown",
236+
"metadata": {},
237+
"source": [
238+
"# Good Job!"
239+
]
26240
}
27241
],
28242
"metadata": {

0 commit comments

Comments
 (0)