Given two sequences A and B of the same length: one is strictly increasing, the other is strictly decreasing.
It is required to find an index i such that the absolute value of the difference between A[i] and B[i] is minimal. If there are several such indices, the answer is the smallest of them. The input sequences are standard Python arrays. It is guaranteed that they are of the same length. Efficiency requirements: Asymptotic complexity: no more than the power of the logarithm of the length of the input sequences.
I have implemented index lookup using the golden section method, but I am confused by the use of floating point arithmetic. Is it possible to somehow improve this algorithm so as not to use it, or can you come up with a more concise solution?
import random
import math
def peak(A,B):
def f(x):
return abs(A[x]-B[x])
phi_inv = 1 / ((math.sqrt(5) + 1) / 2)
def cal_x1(left,right):
return right - (round((right-left) * phi_inv))
def cal_x2(left,right):
return left + (round((right-left) * phi_inv))
left, right = 0, len(A)-1
x1, x2 = cal_x1(left, right), cal_x2(left,right)
while x1 < x2:
if f(x1) > f(x2):
left = x1
x1 = x2
x2 = cal_x1(x1,right)
else:
right = x2
x2 = x1
x1 = cal_x2(left,x2)
if x1 > 1 and f(x1-2) <= f(x1-1): return x1-2
if x1+2 < len(A) and f(x1+2) < f(x1+1): return x1+2
if x1 > 0 and f(x1-1) <= f(x1): return x1-1
if x1+1 < len(A) and f(x1+1) < f(x1): return x1+1
return x1
#value check
def make_arr(inv):
x = set()
while len(x) != 1000:
x.add(random.randint(-10000,10000))
x = sorted(list(x),reverse = inv)
return x
x = make_arr(0)
y = make_arr(1)
needle = 1000000
c = 0
for i in range(1000):
if abs(x[i]-y[i]) < needle:
c = i
needle = abs(x[i]-y[i])
print(c)
print(peak(x,y))
Approach
The poster asks about alternative, simpler solutions to posted code.
The problem is a variant of Leetcode Problem 852, where the goal is to find the peak index in a moutain array. We convert to a peak, rather than min, by computing the negative of the abolute difference. Our aproach is to modify this Python solution to the Leetcode problem.
Code
def binary_search(x, y):
''' Mod of https://walkccc.me/LeetCode/problems/0852/ to use function'''
def f(m):
' Absoute value of difference at index m of two arrays '
return -abs(x[m] - y[m]) # Make negative so we are looking for a peak
# peak using binary search
l = 0
r = len(arr) - 1
while l < r:
m = (l + r) // 2
if f(m) < f(m + 1): # check if increasing
l = m + 1
else:
r = m # was decreasing
return l
Test
def linear_search(A, B):
' Linear Search Method '
values = [abs(ai-bi) for ai, bi in zip(A, B)]
return values.index(min(values)) # linear search
def make_arr(inv):
random.seed(10) # added so we can repeat with the same data
x = set()
while len(x) != 1000:
x.add(random.randint(-10000,10000))
x = sorted(list(x),reverse = inv)
return x
# Create data
x = make_arr(0)
y = make_arr(1)
# Run search methods
print(f'Linear Search Solution {linear_search(x, y)}')
print(f'Golden Section Search Solution {peak(x, y)}') # posted code
print(f'Binary Search Solution {binary_search(x, y)}')
Output
Linear Search Solution 499
Golden Section Search Solution 499
Binary Search Solution 499
I am try to check the intervals over which the function is increasing and the intervals where it is decreasing (The intervals only check in (-oo;0) or (0;+oo) or Real number). Of course my code only serve in simple function such as:
(x^(-5)) ; (x^3 + x) ; (x^4 + 3(x^2) - 1)
The problem here I must input all this function: (sqrt(abs(x))) ; (1/(abs(x)))
When I input all that, I realize when the code run to compare calculation --> It cannot compare and It's error
Example: - Input: (sympy.sqrt(sympy.abs(x)))(I comment in my code where the error take from) - Ouput: Error
import sympy
import math
import inspect
import matplotlib.pyplot as plt
import numpy as np
def check_inc_des(f, x_min=-100, x_max=100, n_sample=100):
x = sympy.symbols('x')
expr = f(x)
limit_expr = sympy.limit(expr, x, 0)
if limit_expr == -math.inf or limit_expr == math.inf:
for k in np.linspace(x_min, -0.5, n_sample):
a = sympy.diff(f(x))
a = a.subs(sympy.Symbol("x"), k)
if a < 0:
b = "The function is decreasing in the interval (-oo;0)"
break
if a > 0:
b = "The function is increasing in the interval (-oo;0)"
break
for k in np.linspace(0.5, x_max, n_sample):
a = sympy.diff(f(x))
a = a.subs(sympy.Symbol("x"), k)
if a > 0:
d = "The function is increasing in the interval (0;+oo)"
break
if a < 0:
d = "The function is decreasing in the interval (0;+oo)"
break
return b + "\n" +" "+ d
else:
for k in np.linspace(x_min, -0.5, n_sample):
a = sympy.diff(f(x))
a = a.subs(sympy.Symbol("x"), k)
if a < 0: #<--------------------------------------------------The error take from here
b = "The function is decreasing in the interval (-oo;0)"
break
if a > 0:
b = "The function is increasing in the interval (-oo;0)"
break
for k in np.linspace(0.5, x_max, n_sample):
h = sympy.diff(f(x))
h = h.subs(sympy.Symbol("x"), k)
if h > 0:
d = "The function is increasing in the interval (0;+oo)"
break
if h < 0:
d = "The function is decreasing in the interval (0;+oo)"
break
if a < 0 and h < 0:
return "The function is decreasing in the Real number"
if a > 0 and h > 0:
return "The function is increasing in the Real number"
return b + "\n"+" "+ d
def do_ex_3(fa):
func_lst = [fa]
for func in func_lst:
print(check_inc_des(func))
return
def f_3x_a(x):
return x**(-5) #<------------------------------------------------------Where I input
do_ex_3(f_3x_a)
My code upper take example for x^(-5): - Input: (x^(-5)) - Ouput: The function is decreasing in the interval (-oo;0)
The function is decreasing in the interval (0;+oo) Thanks for support!
I'm given a problem that explicitly asks me to not use either numpy or pandas
Problem :
Given two set of data points in the form of list of tuples like
Red =[(R11,R12),(R21,R22),(R31,R32),(R41,R42),(R51,R52),..,(Rn1,Rn2)]
Blue=[(B11,B12),(B21,B22),(B31,B32),(B41,B42),(B51,B52),..,(Bm1,Bm2)]
and set of line equations(in the string format, i.e list of strings)
Lines = [a1x+b1y+c1,a2x+b2y+c2,a3x+b3y+c3,a4x+b4y+c4,..,K lines]
Note: You need to do string parsing here and get the coefficients of x,y and intercept.
Your task here is to print "YES"/"NO" for each line given. You should print YES, if all the red points are one side of the line and blue points are on other side of the line, otherwise you should print NO.
Ex:
Red= [(1,1),(2,1),(4,2),(2,4), (-1,4)]
Blue= [(-2,-1),(-1,-2),(-3,-2),(-3,-1),(1,-3)]
Lines=["1x+1y+0","1x-1y+0","1x+0y-3","0x+1y-0.5"]
Output:
YES
NO
NO
YES
Mathematically, you take the equation of the line say S
Suppose S(x)(y) = 1x+1y+0
Now take points (1,1) and (-6,-1)
S(1)(1) = 1(1)+ 1(1) = 2 >0
S(-6)(-1) = 1(-6)+(1)(-1) = -7 <0
Therefore, we can conclude that (1,1) and (-6,-1) lie on different sides of the line S.
Now in the given problem, given an equation S all red should be on one side of the equation and blue on the other side.
The issue here is that, I'm not sure how you substitute values of the points in the lists in the equation given in the form of a string using python.
Also, I'm falling short of coming up with a logic (how to use loops accroding to our requirement) for the code to solve the above to solve the above question.
Would appreciate insights on this question. Thanks in advance.
use your_string.replace() and eval() function,
replace x and y characters with it's values,
eval() to execute string as equation
for element in red:
equation=line.replace('x','*'+str(element[0]))
equation=equation.replace('y','*'+str(element [1]))
result=eval(equation)
if result > 0:
pass
else:
return "NO"
#code for blue
return "Yes"
Assuming you strings are always of the form
ax+by+c
(in that order), you could write
import re
for line in Lines:
a, b, c = [float(coef.strip()) for coef in re.split('x|y', line)]
...
Python3 program to check if two points lie on the same side
def pointsAreOnSameSideOfLine(a, b, c, x1, y1, x2, y2):
fx1 = 0 # Variable to store a * x1 + b * y1 - c
fx2 = 0 # Variable to store a * x2 + b * y2 - c
fx1 = a * x1 + b * y1 - c
fx2 = a * x2 + b * y2 - c
# If fx1 and fx2 have same sign
if ((fx1 * fx2) > 0):
return True
return False
Driver code
a, b, c = 1, 1, 1
x1, y1 = 1, 1
x2, y2 = 2, 1
if (pointsAreOnSameSideOfLine(a, b, c, x1, y1, x2, y2)):
print("Yes")
else:
print("No")
#hemanth ravavarapu, re.split(x|y) will be splitting line equation based on x or y. i.e if you give space then it will split based on space same here also it splitting where ever it found x or y.
e1 = []
e2 = []
def points():
for k in Lines:
a=k[0];b=k[2]+k[3];c=k[5]+k[6]
n = [];m=[]
for i in Red:
x1=i[0];y1=i[1]
eq1 = int(a) * int(x1) + int(b) * int(y1)-int(c)
n.append(eq1)
e1.append(n)
for j in Blue:
x2=j[0];y2=j[1]
eq2 = int(a) * int(x2) + int(b) * int(y2)-int(c)
m.append(eq2)
e2.append(m)
print(e1)
print('----------------------------------------------------------------------')
print(e2)
print('----------------------------------------------------------------------')
p=[]
for i,j in zip(e1,e2):
q = []
for k,l in zip(i,j):
x=k*l
if x<0:
q.append(x)
p.append(q)
print(p)
for i in p:
if len(i)==5:
print('yes')
else:
print('No')
Red= [(1,1),(2,1),(4,2),(2,4),(-1,4)]
Blue= [(-2,-1),(-1,-2),(-3,-2),(-3,-1),(1,-3)]
Lines=["1x+1y+0","1x-1y+0","1x+0y-3","0x+1y-0.5"]
points()
For string parsing :
def getCor(s):
first = s.split('x')
a = float(first[0])
second = first[1].split('y')
b = float(second[0])
c = float(second[1])
return (a,b,c)
getCor('24x+1y-0.5')
Output :
(24.0, 1.0, -0.5)
import math
def getCor(s):
first = s.split('x')
a = float(first[0])
second = first[1].split('y')
b = float(second[0])
c = float(second[1])
return (a,b,c)
def getSide(t,p):
cal = (t[0] * p[0]) + (t[1] * p[1]) + (t[2])
if cal > 0:
return 1
elif cal < 0:
return -1
elif cal == 0:
return 0
return -2
def getAns(red,blue,line):
sign_red = getSide(getCor(line),red[0])
sign_blue = getSide(getCor(line),blue[0])
for j in range(len(red)):
if sign_red != getSide(getCor(line),red[j]):
return 'no'
for j in range(len(blue)):
if sign_blue != getSide(getCor(line),blue[j]):
return 'no'
return 'Yes'
Red= [(1,1),(2,1),(4,2),(2,4), (-1,4)]
Blue= [(-2,-1),(-1,-2),(-3,-2),(-3,-1),(1,-3)]
Lines=["1x+1y+0","1x-1y+0","1x+0y-3","0x+1y-0.5"]
for i in Lines:
ans = getAns(Red, Blue, i)
print(ans)
output:
Yes
no
no
Yes
import math
# write your python code here
# you can take the above example as sample input for your program to test
# it should work for any general input try not to hard code for only given input strings
# you can free to change all these codes/structure
def i_am_the_one(red,blue,line):
# your code
for i in red:
eq=line.replace('x','*'+str(i[0]))
eq=eq.replace('y','*'+str(i[1]))
answer=eval(eq)
if answer>0:
pass
else:
return "NO"
# Code for Blue
for j in blue:
eq1=line.replace('x','*'+str(j[0]))
eq1=eq1.replace('y','*'+str(j[1]))
answer1=eval(eq1)
if answer1<0:
pass
else:
return "NO"
return "Yes"
Red= [(1,1),(2,1),(4,2),(2,4), (-1,4)]
Blue= [(-2,-1),(-1,-2),(-3,-2),(-3,-1),(1,-3)]
Lines=["1x+1y+0","1x-1y+0","1x+0y-3","0x+1y-0.5"]
for i in Lines:
yes_or_no = i_am_the_one(Red, Blue, i)
print(yes_or_no)
I recently implemented Karatsuba Multiplication as a personal exercise. I wrote my implementation in Python following the pseudocode provided on wikipedia:
procedure karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
return num1*num2
/* calculates the size of the numbers */
m = max(size_base10(num1), size_base10(num2))
m2 = m/2
/* split the digit sequences about the middle */
high1, low1 = split_at(num1, m2)
high2, low2 = split_at(num2, m2)
/* 3 calls made to numbers approximately half the size */
z0 = karatsuba(low1, low2)
z1 = karatsuba((low1+high1), (low2+high2))
z2 = karatsuba(high1, high2)
return (z2*10^(2*m2)) + ((z1-z2-z0)*10^(m2)) + (z0)
Here is my python implementation:
def karat(x,y):
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
m = max(len(str(x)),len(str(y)))
m2 = m / 2
a = x / 10**(m2)
b = x % 10**(m2)
c = y / 10**(m2)
d = y % 10**(m2)
z0 = karat(b,d)
z1 = karat((a+b),(c+d))
z2 = karat(a,c)
return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)
My question is about final merge of z0, z1, and z2.
z2 is shifted m digits over (where m is the length of the largest of two multiplied numbers).
Instead of simply multiplying by 10^(m), the algorithm uses *10^(2*m2)* where m2 is m/2.
I tried replacing 2*m2 with m and got incorrect results. I think this has to do with how the numbers are split but I'm not really sure what's going on.
Depending on your Python version you must or should replace / with the explicit floor division operator // which is the appropriate here; it rounds down ensuring that your exponents remain entire numbers.
This is essential for example when splitting your operands in high digits (by floor dividing by 10^m2) and low digits (by taking the residual modulo 10^m2) this would not work with a fractional m2.
It also explains why 2 * (x // 2) does not necessarily equal x but rather x-1 if x is odd.
In the last line of the algorithm 2 m2 is correct because what you are doing is giving a and c their zeros back.
If you are on an older Python version your code may still work because / used to be interpreted as floor division when applied to integers.
def karat(x,y):
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
m = max(len(str(x)),len(str(y)))
m2 = m // 2
a = x // 10**(m2)
b = x % 10**(m2)
c = y // 10**(m2)
d = y % 10**(m2)
z0 = karat(b,d)
z1 = karat((a+b),(c+d))
z2 = karat(a,c)
return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)
i have implemented the same idea but i have restricted to the 2 digit multiplication as the base case because i can reduce float multiplication in function
import math
def multiply(x,y):
sx= str(x)
sy= str(y)
nx= len(sx)
ny= len(sy)
if ny<=2 or nx<=2:
r = int(x)*int(y)
return r
n = nx
if nx>ny:
sy = sy.rjust(nx,"0")
n=nx
elif ny>nx:
sx = sx.rjust(ny,"0")
n=ny
m = n%2
offset = 0
if m != 0:
n+=1
offset = 1
floor = int(math.floor(n/2)) - offset
a = sx[0:floor]
b = sx[floor:n]
c = sy[0:floor]
d = sy[floor:n]
print(a,b,c,d)
ac = multiply(a,c)
bd = multiply(b,d)
ad_bc = multiply((int(a)+int(b)),(int(c)+int(d)))-ac-bd
r = ((10**n)*ac)+((10**(n/2))*ad_bc)+bd
return r
print(multiply(4,5))
print(multiply(4,58779))
print(int(multiply(4872139874092183,5977098709879)))
print(int(4872139874092183*5977098709879))
print(int(multiply(4872349085723098457,597340985723098475)))
print(int(4872349085723098457*597340985723098475))
print(int(multiply(4908347590823749,97098709870985)))
print(int(4908347590823749*97098709870985))
I tried replacing 2*m2 with m and got incorrect results. I think this has to do with how the numbers are split but I'm not really sure what's going on.
This goes to the heart of how you split your numbers for the recursive calls.
If you choose to use an odd n then n//2 will be rounded down to the nearest whole number, meaning your second number will have a length of floor(n/2) and you would have to pad the first with the floor(n/2) zeros.
Since we use the same n for both numbers this applies to both. This means if you stick to the original odd n for the final step, you would be padding the first term with the original n zeros instead of the number of zeros that would result from the combination of the first padding plus the second padding (floor(n/2)*2)
You have used m2 as a float. It needs to be an integer.
def karat(x,y):
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
m = max(len(str(x)),len(str(y)))
m2 = m // 2
a = x // 10**(m2)
b = x % 10**(m2)
c = y // 10**(m2)
d = y % 10**(m2)
z0 = karat(b,d)
z1 = karat((a+b),(c+d))
z2 = karat(a,c)
return (z2 * 10**(2*m2)) + ((z1 - z2 - z0) * 10**(m2)) + (z0)
Your code and logic is correct, there is just issue with your base case. Since according to the algo a,b,c,d are 2 digit numbers you should modify your base case and keep the length of x and y equal to 2 in the base case.
I think it is better if you used math.log10 function to calculate the number of digits instead of converting to string, something like this :
def number_of_digits(number):
"""
Used log10 to find no. of digits
"""
if number > 0:
return int(math.log10(number)) + 1
elif number == 0:
return 1
else:
return int(math.log10(-number)) + 1 # Don't count the '-'
The base case if len(str(x)) == 1 or len(str(y)) == 1: return x*y is incorrect. If you run either of the python code given in answers against large integers, the karat() function will not produce the correct answer.
To make the code correct, you need to change the base case to if len(str(x) < 3 or len(str(y)) < 3: return x*y.
Below is a modified implementation of Paul Panzer's answer that correctly multiplies large integers.
def karat(x,y):
if len(str(x)) < 3 or len(str(y)) < 3:
return x*y
n = max(len(str(x)),len(str(y))) // 2
a = x // 10**(n)
b = x % 10**(n)
c = y // 10**(n)
d = y % 10**(n)
z0 = karat(b,d)
z1 = karat((a+b), (c+d))
z2 = karat(a,c)
return ((10**(2*n))*z2)+((10**n)*(z1-z2-z0))+z0