I am currently trying to solve the problem "Is my friend cheating?" on Codewars.
The Text are the Details to the Problem:
A friend of mine takes the sequence of all numbers from 1 to n (where n > 0).
Within that sequence, he chooses two numbers, a and b.
He says that the product of a and b should be equal to the sum of all numbers in the sequence, excluding a and b.
Given a number n, could you tell me the numbers he excluded from the sequence?
The function takes the parameter: n (n is always strictly greater than 0) and returns an array or a string (depending on the language) of the form:
[(a, b), ...] or [[a, b], ...] or {{a, b}, ...} or or [{a, b}, ...]
with all (a, b) which are the possible removed numbers in the sequence 1 to n.
[(a, b), ...] or [[a, b], ...] or {{a, b}, ...} or ... will be sorted in increasing order of the "a".
It happens that there are several possible (a, b). The function returns an empty array (or an empty string) if no possible numbers are found which will prove that my friend has not told the truth! (Go: in this case return nil).
Examples:
removNb(26) should return [(15, 21), (21, 15)]
or
removNb(26) should return { {15, 21}, {21, 15} }
or
removeNb(26) should return [[15, 21], [21, 15]]
or
removNb(26) should return [ {15, 21}, {21, 15} ]
or
removNb(26) should return "15 21, 21 15"
or
in C:
removNb(26) should return {{15, 21}{21, 15}} tested by way of strings.
Function removNb should return a pointer to an allocated array of Pair pointers, each
one also allocated.
My Code I tried to solve the Problem with:
def removNb(n):
liste = [i+1 for i in range(n)]
result = []
for k in range(n):
for t in range(k,n):
m,n = liste[k], liste[t]
if m * n == sum(liste)-(m+n):
result.append((m, n))
result.append((n, m))
return result
This solution is working, but appently not enough optimised.
Does anyone have an idea how to optimize the Code further.
Since you never mutate this list:
liste = [i+1 for i in range(n)]
it's always just [1, ..., n], so you can replace any expression of the form liste[x] with just x + 1. And instead of computing sum(liste) repeatedly, you can just do it once. Applying those changes leaves you with:
def removNb(n):
total = sum(range(n + 1))
result = []
for k in range(n):
for t in range(k, n):
m, n = k + 1, t + 1
if m * n == total - (m + n):
result.append((m, n))
result.append((n, m))
return result
We can further eliminate the + 1s by modifying our ranges:
def removNb(n):
total = sum(range(n + 1))
result = []
for k in range(1, n + 1):
for t in range(k, n + 1):
m, n = k, t
if m * n == total - (m + n):
result.append((m, n))
result.append((n, m))
return result
which also makes the m, n assignment superfluous (also shadowing n inside the loop was confusing):
def removNb(n):
total = sum(range(n + 1))
result = []
for k in range(1, n + 1):
for t in range(k, n + 1):
if k * t == total - (k + t):
result.append((k, t))
result.append((t, k))
return result
You're recomputing sum(liste) for every iteration of the inner loop. This takes your runtime from O(n^2) to O(n^3).
Here's a quick fix:
def removNb(n):
nums = list(range(1, n + 1))
result = []
total = sum(nums)
for k in range(n):
for t in range(k,n):
m, n = nums[k], nums[t]
if m * n == total - (m + n):
result.append((m, n))
result.append((n, m))
return result
print(removNb(26))
If that still isn't fast enough, you can also cut down the runtime from O(n^2) to O(n log n) by using a binary rather than linear search in the inner loop.
Related
I have integer input: 0 < a, K, N < 10^9
I need to find all b numbers that satisfy:
a + b <= N
(a + b) % K = 0
For example: 10 6 40 -> [2, 8, 14, 20, 26]
I tried a simple brute force and failed (Time Limit Exceeded). Can anyone suggest answer? Thanks
a, K, N = [int(x) for x in input().split()]
count = 0
b = 1
while (a + b <= N):
if ((a + b) % K) == 0:
count+=1
print(b, end=" ")
b+=1
if (count == 0):
print(-1)
The first condition is trivial in the sense that it just poses an upper limit on b. The second condition can be rephrased using the definition of % as
a + b = P * K
For some arbitrary integer P. From this, is simple to compute the smallest b by finding the smallest P that gives you a positive result for P * K - a. In other words
P * K - a >= 0
P * K >= a
P >= a / K
P = ceil(a / K)
So you have
b0 = ceil(a / K) * K - a
b = range(b0, N + 1, K)
range is a generator, so it won't compute the values up front. You can force that by doing list(b).
At the same time, if you only need the count of elements, range objects will do the math on the limits and step size for you conveniently, all without computing the actual values, so you can just do len(b).
To find the list of bs, you can use some maths. First, we note that (a + b) % K is equivalent to a % K + b % K. Also when n % K is 0, that means that n is a multiple of K. So the smallest value of b is n * K - a for the smallest value of n where this calculation is still positive. Once you find that value, you can simply add K repeatedly to find all other values of b.
b = k - a%k
Example: a=19, k=11, b = 11-19%11 = 11-8 =3
Using Python, I would like to implement a function that takes a natural number n as input and outputs a list of natural numbers [y1, y2, y3, ...] such that n + y1*y1 and n + y2*y2 and n + y3*y3 and so forth is again a square.
What I tried so far is to obtain one y-value using the following function:
def find_square(n:int) -> tuple[int, int]:
if n%2 == 1:
y = (n-1)//2
x = n+y*y
return (y,x)
return None
It works fine, eg. find_square(13689) gives me a correct solution y=6844. It would be great to have an algorithm that yields all possible y-values such as y=44 or y=156.
Simplest slow approach is of course for given N just to iterate all possible Y and check if N + Y^2 is square.
But there is a much faster approach using integer Factorization technique:
Lets notice that to solve equation N + Y^2 = X^2, that is to find all integer pairs (X, Y) for given fixed integer N, we can rewrite this equation to N = X^2 - Y^2 = (X + Y) * (X - Y) which follows from famous school formula of difference of squares.
Now lets rename two factors as A, B i.e. N = (X + Y) * (X - Y) = A * B, which means that X = (A + B) / 2 and Y = (A - B) / 2.
Notice that A and B should be of same odditiy, either both odd or both even, otherwise in last formulas above we can't have whole division by 2.
We will factorize N into all possible pairs of two factors (A, B) of same oddity. For fast factorization in code below I used simple to implement but yet quite fast algorithm Pollard Rho, also two extra algorithms were needed as a helper to Pollard Rho, one is Fermat Primality Test (which allows fast checking if number is probably prime) and second is Trial Division Factorization (which helps Pollard Rho to factor out small factors, which could cause Pollard Rho to fail).
Pollard Rho for composite number has time complexity O(N^(1/4)) which is very fast even for 64-bit numbers. Any faster factorization algorithm can be chosen if needed a bigger space to be searched. My fast algorithm time is dominated by speed of factorization, remaining part of algorithm is blazingly fast, just few iterations of loop with simple formulas.
If your N is a square itself (hence we know its root easily), then Pollard Rho can factor N even much faster, within O(N^(1/8)) time. Even for 128-bit numbers it means very small time, 2^16 operations, and I hope you're solving your task for less than 128 bit numbers.
If you want to process a range of possible N values then fastest way to factorize them is to use techniques similar to Sieve of Erathosthenes, using set of prime numbers, it allows to compute all factors for all N numbers within some range. Using Sieve of Erathosthenes for the case of range of Ns is much faster than factorizing each N with Pollard Rho.
After factoring N into pairs (A, B) we compute (X, Y) based on (A, B) by formulas above. And output resulting Y as a solution of fast algorithm.
Following code as an example is implemented in pure Python. Of course one can use Numba to speed it up, Numba usually gives 30-200 times speedup, for Python it achieves same speed as optimized C++. But I thought that main thing here is to implement fast algorithm, Numba optimizations can be done easily afterwards.
I added time measurement into following code. Although it is pure Python still my fast algorithm achieves 8500x times speedup compared to regular brute force approach for limit of 1 000 000.
You can change limit variable to tweak amount of searched space, or num_tests variable to tweak amount of different tests.
Following code implements both solutions - fast solution find_fast() described above plus very tiny brute force solution find_slow() which is very slow as it scans all possible candidates. This slow solution is only used to compare correctness in tests and compare speedup.
Code below uses nothing except few standard Python library modules, no external modules were used.
Try it online!
def find_slow(N):
import math
def is_square(x):
root = int(math.sqrt(float(x)) + 0.5)
return root * root == x, root
l = []
for y in range(N):
if is_square(N + y ** 2)[0]:
l.append(y)
return l
def find_fast(N):
import itertools, functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = factor(N)
mfs = {}
for e in fs:
mfs[e] = mfs.get(e, 0) + 1
fs = sorted(mfs.items())
del mfs
Ys = set()
for take_a in itertools.product(*[
(range(v + 1) if k != 2 else range(1, v)) for k, v in fs]):
A = Prod([p ** t for (p, _), t in zip(fs, take_a)])
B = N // A
assert A * B == N, (N, A, B, take_a)
if A < B:
continue
X = (A + B) // 2
Y = (A - B) // 2
assert N + Y ** 2 == X ** 2, (N, A, B, X, Y)
Ys.add(Y)
return sorted(Ys)
def trial_div_factor(n, limit = None):
# https://en.wikipedia.org/wiki/Trial_division
fs = []
while n & 1 == 0:
fs.append(2)
n >>= 1
all_checked = False
for d in range(3, (limit or n) + 1, 2):
if d * d > n:
all_checked = True
break
while True:
q, r = divmod(n, d)
if r != 0:
break
fs.append(d)
n = q
if n > 1 and all_checked:
fs.append(n)
n = 1
return fs, n
def fermat_prp(n, trials = 32):
# https://en.wikipedia.org/wiki/Fermat_primality_test
import random
if n <= 16:
return n in (2, 3, 5, 7, 11, 13)
for i in range(trials):
if pow(random.randint(2, n - 2), n - 1, n) != 1:
return False
return True
def pollard_rho_factor(n):
# https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
import math, random
fs, n = trial_div_factor(n, 1 << 7)
if n <= 1:
return fs
if fermat_prp(n):
return sorted(fs + [n])
for itry in range(8):
failed = False
x = random.randint(2, n - 2)
for cycle in range(1, 1 << 60):
y = x
for i in range(1 << cycle):
x = (x * x + 1) % n
d = math.gcd(x - y, n)
if d == 1:
continue
if d == n:
failed = True
break
return sorted(fs + pollard_rho_factor(d) + pollard_rho_factor(n // d))
if failed:
break
assert False, f'Pollard Rho failed! n = {n}'
def factor(N):
import functools
Prod = lambda it: functools.reduce(lambda a, b: a * b, it, 1)
fs = pollard_rho_factor(N)
assert N == Prod(fs), (N, fs)
return sorted(fs)
def test():
import random, time
limit = 1 << 20
num_tests = 20
t0, t1 = 0, 0
for i in range(num_tests):
if (round(i / num_tests * 1000)) % 100 == 0 or i + 1 >= num_tests:
print(f'test {i}, ', end = '', flush = True)
N = random.randrange(limit)
tb = time.time()
r0 = find_slow(N)
t0 += time.time() - tb
tb = time.time()
r1 = find_fast(N)
t1 += time.time() - tb
assert r0 == r1, (N, r0, r1, t0, t1)
print(f'\nTime slow {t0:.05f} sec, fast {t1:.05f} sec, speedup {round(t0 / max(1e-6, t1))} times')
if __name__ == '__main__':
test()
Output:
test 0, test 2, test 4, test 6, test 8, test 10, test 12, test 14, test 16, test 18, test 19,
Time slow 26.28198 sec, fast 0.00301 sec, speedup 8732 times
For the easiest solution, you can try this:
import math
n=13689 #or we can ask user to input a square number.
for i in range(1,9999):
if math.sqrt(n+i**2).is_integer():
print(i)
For a user input n, and 1<=i<j<=n, find the number of pairs where i*i*i=j*j using python
The program needs to take input from the user and if user input is 50, the output should be 3 as there are 3 such pairs :(1,1), (4,8), (9,27)using python.
def solution(n):
count=0
for i in range(1,n):
for j in range(i,n):
if (i**3==j*j):
count+=1
return count
n=int(input())
out=solution(n)
print(out)
This is the function I wrote. It works, but in the site I am practicing, it times out and asks me to optimize it further. What can I do?
You may not count how many time you find a match, but save the indices :
def solution(n):
result = []
for i in range(1, n):
for j in range(i, n):
if i ** 3 == j ** 2:
result.append((i, j))
return result
# with list comprehension
def solution(n):
return [(i, j) for i in range(1, n) for j in range(i, n) if i ** 3 == j ** 2]
OPTIMIZE
By looking at the values, you can determine which values can match, to get i**2 == j**3 t=you need i = x**3 and j = x**2 so one loop is sufficient :
def solution(n):
result = []
for i in range(1, ceil(n ** (1 / 3))):
result.append((i ** 2, i ** 3))
return result
# with list comprehension
def solution(n):
return [(i ** 2, i ** 3) for i in range(1, ceil(n ** (1 / 3)))]
Being a programmer should not prevent to keep one minute away from the computer and thinking about the mathematical problem. As an integer can be factorized as a product of prime factors at a power, i and j have to share the same prime factors, and the equality will be true for each of those prime factors. But for prime factors is is evident that you need to have a common number k with: k2 = i and k3 = j.
So the problem can be reduced to finding all numbers k, k >= 1 and k3 <= n. And the i,j pairs if you need them are just k2, k3
A trivial way is:
def solution(n)
count = 0
for i in range(n):
if i * i * i * i * i * i <= n:
count += 1
else:
break
return count
with one single loop.
But you can guess that the result will be close to n1/6, which will lead immediately to the result:
def solution(n):
def i6(i):
j = i *i * i
return j * j
i = int(n ** (1./6))
if (i == 0): return 1 # should never occur but floating point
# inaccuracy can give WEIRD results
if i6(i) > n:
return i - 1 # still floating point inaccuracy
if i6(i+1) <= n: # over convervative
return i + 1
return i
Only 3 tests whatever the value of n, at least up to 248 (mantissa size of a double value)
I have two sets like A={0,1,2,...,i} and B={3,6,10,15}, a constant $s$, and a specified number $n$ which belongs to the natural numbers set.
I want to find a/all combinations that satisfy a_1*b_1+a_2*b_2+\dots+a_n*b_n>=s
For example, if s=25, n=2 each of following answers is acceptable 1*10+1*15 , 2*10+1*6 , 0+2*15 or 4*3+2*6
If I didn't have the second set it would be easy because the problem reduces to producing random partitions with predetermined sum s as introduced in here
How should I efficiently implement this in python? any mathematical way to do it?
It also reminds me of some kind of equation but I'm not sure what I should search for.
I appreciate any hint.
Edit: It is important for me to have exactly "n" terms in my answer and there is chance for other alternatives. In my example, each of four answers should have a chance for generation. In other words, I have "n" place to fill them with my terms such that their sum equals to "s". Sorry not to clear it at first place.
It can be done by straight-forward recursion.
from functools import lru_cache
def find_combinations(numbers, threshold, nterms, maxcoeff, stringify=True):
numbers = sorted(numbers, reverse=True)
#lru_cache(None)
def rec(k, s, n):
if s > maxcoeff * numbers[k]:
top = maxcoeff
res = []
else:
top = (s-1) // numbers[k]
res = [[top + 1]]
if n > 1 and k < len(numbers)-1:
for j in range(top, -1, -1):
res.extend([[j, *subres] for subres in rec(
k+1, s-j*numbers[k], n-(j!=0))])
return res
if stringify:
return [' + '.join(f'{c}\u2a2f{n}' for c, n in zip(sol, numbers) if c)
for sol in rec(0, threshold, nterms)]
else:
return rec(0, threshold, nterms)
print(find_combinations({3, 6, 10, 15}, 25, 2, 2))
Prints:
['2⨯15', '1⨯15 + 1⨯10', '2⨯10 + 1⨯6']
Update: allowing numbers to occcur multiple times (these are lumped together, basically maxcoeff is multiplied with the number of occurrences of each number):
def find_combinations_with_replacement(numbers, threshold, nterms, maxcoeff,
stringify=True):
numbers = sorted(numbers, reverse=True)
#lru_cache(None)
def rec(k, s, n):
if s > maxcoeff * numbers[k] * n:
return []
top = (s-1) // numbers[k]
res = [[top + 1]]
if n > 1 and k < len(numbers)-1:
for j in range(top, -1, -1):
res.extend([[j, *subres] for subres in rec(
k+1, s-j*numbers[k], n - (j-1) // maxcoeff - 1)])
return res
if stringify:
return [' + '.join(f'{c}\u2a2f{n}' for c, n in zip(sol, numbers) if c)
for sol in rec(0, threshold, nterms)]
else:
return rec(0, threshold, nterms)
print(find_combinations_with_replacement({3, 6, 10, 15}, 25, 4, 1))
Prints:
['2⨯15', '1⨯15 + 1⨯10', '1⨯15 + 2⨯6', '1⨯15 + 1⨯6 + 2⨯3', '3⨯10', '2⨯10 + 1⨯6', '2⨯10 + 2⨯3', '1⨯10 + 3⨯6', '1⨯10 + 2⨯6 + 1⨯3']
What is the fastest way to swap two digits in a number in Python? I am given the numbers as strings, so it'd be nice if I could have something as fast as
string[j] = string[j] ^ string[j+1]
string[j+1] = string[j] ^ string[j+1]
string[j] = string[j] ^ string[j+1]
Everything I've seen has been much more expensive than it would be in C, and involves making a list and then converting the list back or some variant thereof.
This is faster than you might think, at least faster than Jon Clements' current answer in my timing test:
i, j = (i, j) if i < j else (j, i) # make sure i < j
s = s[:i] + s[j] + s[i+1:j] + s[i] + s[j+1:]
Here's my test bed should you want to compare any other answers you get:
import timeit
import types
N = 10000
R = 3
SUFFIX = '_test'
SUFFIX_LEN = len(SUFFIX)
def setup():
import random
global s, i, j
s = 'abcdefghijklmnopqrstuvwxyz'
i = random.randrange(len(s))
while True:
j = random.randrange(len(s))
if i != j: break
def swapchars_martineau(s, i, j):
i, j = (i, j) if i < j else (j, i) # make sure i < j
return s[:i] + s[j] + s[i+1:j] + s[i] + s[j+1:]
def swapchars_martineau_test():
global s, i, j
swapchars_martineau(s, i, j)
def swapchars_clements(text, fst, snd):
ba = bytearray(text)
ba[fst], ba[snd] = ba[snd], ba[fst]
return str(ba)
def swapchars_clements_test():
global s, i, j
swapchars_clements(s, i, j)
# find all the functions named *SUFFIX in the global namespace
funcs = tuple(value for id,value in globals().items()
if id.endswith(SUFFIX) and type(value) is types.FunctionType)
# run the timing tests and collect results
timings = [(f.func_name[:-SUFFIX_LEN],
min(timeit.repeat(f, setup=setup, repeat=R, number=N))
) for f in funcs]
timings.sort(key=lambda x: x[1]) # sort by speed
fastest = timings[0][1] # time fastest one took to run
longest = max(len(t[0]) for t in timings) # len of longest func name (w/o suffix)
print 'fastest to slowest *_test() function timings:\n' \
' {:,d} chars, {:,d} timeit calls, best of {:d}\n'.format(len(s), N, R)
def times_slower(speed, fastest):
return speed/fastest - 1.0
for i in timings:
print "{0:>{width}}{suffix}() : {1:.4f} ({2:.2f} times slower)".format(
i[0], i[1], times_slower(i[1], fastest), width=longest, suffix=SUFFIX)
Addendum:
For the special case of swapping digit characters in a positive decimal number given as a string, the following also works and is a tiny bit faster than the general version at the top of my answer.
The somewhat involved conversion back to a string at the end with the format() method is to deal with cases where a zero got moved to the front of the string. I present it mainly as a curiosity, since it's fairly incomprehensible unless you grasp what it does mathematically. It also doesn't handle negative numbers.
n = int(s)
len_s = len(s)
ord_0 = ord('0')
di = ord(s[i])-ord_0
dj = ord(s[j])-ord_0
pi = 10**(len_s-(i+1))
pj = 10**(len_s-(j+1))
s = '{:0{width}d}'.format(n + (dj-di)*pi + (di-dj)*pj, width=len_s)
It has to be of a mutable type of some sort, the best I can think of is (can't make any claims as to performance though):
def swapchar(text, fst, snd):
ba = bytearray(text)
ba[fst], ba[snd] = ba[snd], ba[fst]
return ba
>>> swapchar('thequickbrownfox', 3, 7)
bytearray(b'thekuicqbrownfox')
You can still utilise the result as a str/list - or explicitly convert it to a str if needs be.
>>> int1 = 2
>>> int2 = 3
>>> eval(str(int1)+str(int2))
23
I know you've already accepted an answer, so I won't bother coding it in Python, but here's how you could do it in JavaScript which also has immutable strings:
function swapchar(string, j)
{
return string.replace(RegExp("(.{" + j + "})(.)(.)"), "$1$3$2");
}
Obviously if j isn't in an appropriate range then it just returns the original string.
Given an integer n and two (zero-started) indexes i and j of digits to swap, this can be done using powers of ten to locate the digits, division and modulo operations to extract them, and subtraction and addition to perform the swap.
def swapDigits(n, i, j):
# These powers of 10 encode the locations i and j in n.
power_i = 10 ** i
power_j = 10 ** j
# Retrieve digits [i] and [j] from n.
digit_i = (n // power_i) % 10
digit_j = (n // power_j) % 10
# Remove digits [i] and [j] from n.
n -= digit_i * power_i
n -= digit_j * power_j
# Insert digit [i] in position [j] and vice versa.
n += digit_i * power_j
n += digit_j * power_i
return n
For example:
>>> swapDigits(9876543210, 4, 0)
9876503214
>>> swapDigits(9876543210, 7, 2)
9826543710