2101. Detonate the Maximum Bombs, why is one code optimized than another - python-3.x

I am trying to solve https://leetcode.com/problems/detonate-the-maximum-bombs/
the accepted solution is https://www.youtube.com/watch?v=mEB2y5_Aoos
'''
class Solution:
def maximumDetonation(self, bombs) -> int:
adj,m = defaultdict(list), len(bombs)
def canDetonate(b1,b2):
x1,y1,r1 = b1
x2,y2,r2 = b2
return (x1 - x2) ** 2 + (y1 - y2) ** 2 <= r1 ** 2
for i in range(m):
for j in range(m):
if i==j:
continue
if canDetonate(bombs[i],bombs[j]):
adj[i].append(j)
def dfs(node, seen):
seen.add(node)
for nei in adj[node]:
if nei not in seen:
dfs(nei, seen)
ctr = 0
for idx, bomb in enumerate(bombs):
seen = set()
dfs(idx,seen)
ctr = max(ctr,len(seen))
return ctr
'''
and solution I came up with is as follows:
'''
class Solution:
def isReachable(self, i1, i2, bombs) -> bool:
x1, y1, r1 = bombs[i1]
x2, y2, r2 = bombs[i2]
sol = (x1 - x2) ** 2 + (y1 - y2) ** 2 <= r1 ** 2
return sol
def maximumDetonation(self, bombs) -> int:
maxBombs = 0
def dfs(i, visited):
nonlocal maxBombs
#if bomb visited, return otherwise add to visited.
if i in visited:
return
visited.add(i)
for index in range(len(bombs)):
#for each unvisited bomb, running dfs on all other bombs.
if index not in visited and self.isReachable(i, index, bombs):
dfs(index, visited)
maxBombs = max(maxBombs, len(visited))
for i in range(len(bombs)):
#for each node i am running dfs to check how many bombs explode.
visit = set()
dfs(i, visit)
return maxBombs
'''
both solutions give correct answers for all test cases but I am wondering why their solution is more optimised than mine, as I am doing essentially the same thing. My solution keeps getting time limits exceeding error.

Related

Adaptive Runge-Kutta 4 method

I am trying to find the solution of DEQ dy/dx = 10*e^(-88.8888889(x-2)^2) - 0.6y.
Function:
def dydx(x,y):
return -0.6*y + 10*np.exp(-(x-2)**2/(2*.075**2))
Single Step Solution:
def direct(x,y,h):
k1 = dydx(x,y)
k2 = dydx(x+h/2, y+k1*h/2)
k3 = dydx(x+h/2, y+k2*h/2)
k4 = dydx(x+h, y+k3*h)
y = y + (1/6)*(k1+2*k2+2*k3+k4)*h
return y
Double Step Solution:
def halving(x,y,h):
h = h/2
xh = np.zeros(3)
yh = np.zeros(3)
xh[0] = x
yh[0] = y
for j in range(0,2):
k1 = dydx(xh[j],yh[j])
k2 = dydx(xh[j]+h/2, yh[j]+k1*h/2)
k3 = dydx(xh[j]+h/2, yh[j]+k2*h/2)
k4 = dydx(xh[j]+h, yh[j]+k3*h)
yh[j+1] = yh[j] + (1/6)*(k1+2*k2+2*k3+k4)*h
xh[j+1] = xh[j] + h
return yh[2]
Find the adaptive step size 'h'
def adapt(x,y,h):
error = abs(direct(x,y,h)) - abs(halving(x,y,h)) # it checks whether h falls between a range or not
if error <= 0.01 and error >= .001:
return h
elif error > 0.01:
return adapt(x,y,h/2) # if error is large recalling adapt function with h/2
elif error < .001:
return adapt(x,y,2*h) # 2*h if error is small
Main Driver Program
def rk4(xi,yi,h,xlim):
nval = int((xlim-xi)/h)
x = np.zeros(nval+1)
y = np.zeros(nval+1)
x[0] = xi
y[0] = yi
for i in range(0,nval):
h = adapt(x[i],y[i],h)
y[i+1] = direct(x[i],y[i],h)
x[i+1] = x[i] + h
return x,y
Evaluate using
rk4(0,0.5,.1,4)
I am using jupyter notebook. This program crashes. Probably the recursion section. But why? The error should have been within range after a few recursive call?

How to implement gradient descent algorithms using partial derivatives?

For this question, I want to use gradient descent to minimize the function value to zero for the function x^2 + y^2 with the point (1,1) as the initial starting point. However, I get this error when I try to run my code. I'm not sure why I get that error. Here is what I have so far. Can anyone please help me out? Thanks
Error: xnew = x0-alpha*grad(x0, y0)
TypeError: 'int' object is not callable
def f(x,y):
return x**2 + y**2
def dfdx(x,y):
return 2*x
def dfdy(x,y):
return 2*y
def grad(x,y):
return [dfdx(x,y), dfdy(x,y)]
x0 = 1
y0 = 1
def grad2(f, grad, x0, y0, alpha):
iterations = 0
maxIterations = 1000
while iterations < maxIterations:
xnew = x0-alpha*grad(x0, y0)
ynew = y0-alpha*grad(x0,y0)
x0 = xnew
y0 = ynew
iterations += 1
return xnew, ynew

Programming Secant Method into Python

The sum of two numbers is 20. If each number is added to its square root, the product of the two sums is 155.55. Use Secant Method to approximate, to within 10^(-4), the value of the two numbers.
Based on http://campus.murraystate.edu/academic/faculty/wlyle/420/Secant.htm
#inital guess
x1 = 10
x2 = 50
Epsilon = 1e-4
#given function
def func(x):
return abs(x)**0.5 * (abs(x)+20)**0.5 - 155.55
y1 = func(x1)
y2 = func(x2)
#loop max 20 times
for i in range(20):
ans = x2 - y2 * (x2-x1)/(y2-y1)
y3 = func(ans)
print("Try:{}\tx1:{:0.3f}\tx2:{:0.3f}\ty3:{:0.3f}".format(i,x1, x2, y3))
if (abs(y3) < Epsilon):
break
x1, x2 = x2, ans
y1, y2 = y2, y3
print("\n\nThe numbers are: {:0.3f} and {:0.3f}".format(ans, ans+20))
Based on Your Title
This code works well in most of the cases. Taken from Secant Method Using Python (Output Included)
# Defining Function
def f(x):
return x**3 - 5*x - 9
# Implementing Secant Method
def secant(x0,x1,e,N):
print('\n\n*** SECANT METHOD IMPLEMENTATION ***')
step = 1
condition = True
while condition:
if f(x0) == f(x1):
print('Divide by zero error!')
break
x2 = x0 - (x1-x0)*f(x0)/( f(x1) - f(x0) )
print('Iteration-%d, x2 = %0.6f and f(x2) = %0.6f' % (step, x2, f(x2)))
x0 = x1
x1 = x2
step = step + 1
if step > N:
print('Not Convergent!')
break
condition = abs(f(x2)) > e
print('\n Required root is: %0.8f' % x2)
# Input Section
x0 = input('Enter First Guess: ')
x1 = input('Enter Second Guess: ')
e = input('Tolerable Error: ')
N = input('Maximum Step: ')
# Converting x0 and e to float
x0 = float(x0)
x1 = float(x1)
e = float(e)
# Converting N to integer
N = int(N)
#Note: You can combine above three section like this
# x0 = float(input('Enter First Guess: '))
# x1 = float(input('Enter Second Guess: '))
# e = float(input('Tolerable Error: '))
# N = int(input('Maximum Step: '))
# Starting Secant Method
secant(x0,x1,e,N)

How to make algorithm of counting big negative numbers faster?

I was trying to do a program which can take square matrix of any size and find two any square submatrixes(they shouldn't overlap), whose qualities are the closest. So every elementary square in matrix has a quality(any number). The problem is algorithm is too slow with processing matrixes 100*100 containing big negative numbers(-10^8).
from collections import defaultdict
from math import fsum
from itertools import islice, count
def matrix():
matritsa = list()
koord = list()
ssum = 0
diff = defaultdict(list)
size = int(input()) #size of the matrix
for line in range(size):
matritsa += list(map(int,input().split())) #filling the matrix
Q1,Q2 = map(int,input().split()) #quality range
for i in range(len(matritsa)):
element = matritsa[i]
if Q1 <= element and element <= Q2: #checking if an element is in range
koord.append([element, i//size, i%size, 1]) #coordinates of 1*1 elements
for razmer in range(2,size): #taking squares of 2+ size
#print("Razmer: ",razmer)
for a in range(len(matritsa)):
(x,y) = a//size,a%size #coordinates of the left top square
if y + razmer > size:
continue
ssum = 0
for b in range(x,x+razmer):
ssum += sum(matritsa[b*size+y:b*size+(y+razmer)])
if Q1 <= ssum and ssum <= Q2: #checking if it is in quality range
koord.append([ssum,x,y,razmer])
#print(koord)
#print("Coordinate: {0},{1}; ssum: {2}".format(x,y,ssum))
if x + razmer == size and y + razmer == size:
#print("Final: {0},{1}".format(x,y))
break
g = 0
temp = len(koord)
while g != temp:
(value1,x1,y1,a) = koord[g]
for i in range(g,temp - 1):
(value2,x2,y2,b) = koord[i+1]
if y1 >= y2 + b or y2 >= y1 + a:
diff[abs(value1 - value2)].append([value1,value2])
if x1 >= x2 + b or x2 >= x1 + a:
diff[abs(value1 - value2)].append([value1,value2])
g += 1
minimum = min(diff.keys())
if minimum == 0:
print(*max(diff[minimum]))
elif len(diff[minimum]) > 1:
maximum = sum(diff[minimum][0])
result = diff[minimum][0]
for pair in diff[minimum]:
if sum(pair) > maximum:
maximum = sum(pair)
result = pair
The problem is in this part
g = 0
temp = len(koord)
print(temp)
while g != temp:
(value1,x1,y1,a) = koord[g]
for i in range(g,temp - 1):
(value2,x2,y2,b) = koord[i+1]
if y1 >= y2 + b or y2 >= y1 + a:
diff[abs(value1 - value2)].append([value1,value2])
if x1 >= x2 + b or x2 >= x1 + a:
diff[abs(value1 - value2)].append([value1,value2])
g += 1

Smoothing values (neighbors between 1-9)

Instructions: Compute and store R=1000 random values from 0-1 as x. moving_window_average(x, n_neighbors) is pre-loaded into memory from 3a. Compute the moving window average for x for the range of n_neighbors 1-9. Store x as well as each of these averages as consecutive lists in a list called Y.
My solution:
R = 1000
n_neighbors = 9
x = [random.uniform(0,1) for i in range(R)]
Y = [moving_window_average(x, n_neighbors) for n_neighbors in range(1,n_neighbors)]
where moving_window_average(x, n_neighbors) is a function as follows:
def moving_window_average(x, n_neighbors=1):
n = len(x)
width = n_neighbors*2 + 1
x = [x[0]]*n_neighbors + x + [x[-1]]*n_neighbors
# To complete the function,
# return a list of the mean of values from i to i+width for all values i from 0 to n-1.
mean_values=[]
for i in range(1,n+1):
mean_values.append((x[i-1] + x[i] + x[i+1])/width)
return (mean_values)
This gives me an error, Check your usage of Y again. Even though I've tested for a few values, I did not get yet why there is a problem with this exercise. Did I just misunderstand something?
The instruction tells you to compute moving averages for all neighbors ranging from 1 to 9. So the below code should work:
import random
random.seed(1)
R = 1000
x = []
for i in range(R):
num = random.uniform(0,1)
x.append(num)
Y = []
Y.append(x)
for i in range(1,10):
mov_avg = moving_window_average(x, n_neighbors=i)
Y.append(mov_avg)
Actually your moving_window_average(list, n_neighbors) function is not going to work with a n_neighbors bigger than one, I mean, the interpreter won't say a thing, but you're not delivering correctness on what you have been asked.
I suggest you to use something like:
def moving_window_average(x, n_neighbors=1):
n = len(x)
width = n_neighbors*2 + 1
x = [x[0]]*n_neighbors + x + [x[-1]]*n_neighbors
mean_values = []
for i in range(n):
temp = x[i: i+width]
sum_= 0
for elm in temp:
sum_+= elm
mean_values.append(sum_ / width)
return mean_values
My solution for +100XP
import random
random.seed(1)
R=1000
Y = list()
x = [random.uniform(0, 1) for num in range(R)]
for n_neighbors in range(10):
Y.append(moving_window_average(x, n_neighbors))

Resources