Count all sub-arrays having sum divisible by k - python

While I was studying for interviews, I found this question and solution on GeeksForGeeks, but don't understand the solution.
What it says is
Let there be a subarray (i, j) whose sum is divisible by k
sum(i, j) = sum(0, j) - sum(0, i-1)
Sum for any subarray can be written as q*k + rem where q is a
quotient and rem is remainder Thus,
sum(i, j) = (q1 * k + rem1) - (q2 * k + rem2)
sum(i, j) = (q1 - q2)k + rem1-rem2
We see, for sum(i, j) i.e. for sum of any subarray to be
divisible by k, the RHS should also be divisible by k.
(q1 - q2)k is obviously divisible by k, for (rem1-rem2) to
follow the same, rem1 = rem2 where
rem1 = Sum of subarray (0, j) % k
rem2 = Sum of subarray (0, i-1) % k
First of all, I don't get what q1 and q2 indicate.
def subCount(arr, n, k):
# create auxiliary hash
# array to count frequency
# of remainders
mod =[]
for i in range(k + 1):
mod.append(0)
cumSum = 0
for i in range(n):
cumSum = cumSum + arr[i]
mod[((cumSum % k)+k)% k]= mod[((cumSum % k)+k)% k] + 1
result = 0 # Initialize result
# Traverse mod[]
for i in range(k):
if (mod[i] > 1):
result = result + (mod[i]*(mod[i]-1))//2
result = result + mod[0]
return result
And in this solution code, I don't get the role of mod. What is the effect of incrementing the cound of ((cumSum % k)+k)% kth array?
It would be great if this can be explained step by step easily. Thanks.

Are you familiar with integer modulo/remainder operation?
7 modulo 3 = 1 because
7 = 2 * 3 + 1
compare
N % M = r
because N might be represented as
N = q * M + r
here r is remainder and q is result of integer division like
7 // 3 = 2
For modulo k there might be k distinct remainders 0..k-1
mod array contains counters for every possible remainder. When remainder for every subrange sum is calculated, corresponding counter is incremented, so resulting mod array data looks like [3,2,5,0,7] three zero remainders, two remainders are equal to 1...

Related

Find b that (a+b) divisible to K

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

Trying to define one of Euler's approximations to pi, getting unsupported operand type(s) for 'list and 'int'

I am trying to define a function which will approximate pi in python using one of Euler's methods. His formula is as follows:
My code so far is this:
def pi_euler1(n):
numerator = list(range(2 , n))
for i in numerator:
j = 2
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 1
for k in numerator:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
#Because all primes are odd, both numbers inbetween them are divisible by 2,
#and by extension 1 of the 2 numbers is divisible by 4
term = numerator / denominator
I know this is wrong, and also incomplete. I'm just not quite sure what the TypeError that I mentioned earlier actually means. I'm just quite stuck with it, I want to create a list of the terms and then find their products. Am I on the right lines?
Update:
I have worked ways around this, fixing the clearly obvious errors that were prevalent thanks to msconi and Johanc, now with the following code:
import math
def pi_euler1(n):
numerator = list(range(2 , 13 + math.ceil(n*(math.log(n)+math.log(math.log(n))))))
denominator=[]
for i in numerator:
j = 2
while i * j <= numerator[-1]:
if (i * j) in numerator:
numerator.remove(i * j)
j += 1
numerator.remove(2)
for k in numerator:
if (k + 1) % 4 == 0:
denominator.append(k+1)
else:
denominator.append(k-1)
a=1
for i in range(n):
a *= numerator[i] / denominator[i]
return 4*a
This seems to work, when I tried to plot a graph of the errors from pi in a semilogy axes scale, I was getting a domain error, but i needed to change the upper bound of the range to n+1 because log(0) is undefined. Thank you guys
Here is the code with some small modifications to get it working:
import math
def pi_euler1(n):
lim = n * n + 4
numerator = list(range(3, lim, 2))
for i in numerator:
j = 3
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 2
euler_product = 1
for k in numerator[:n]:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
factor = k / denominator
euler_product *= factor
return euler_product * 4
print(pi_euler1(3))
print(pi_euler1(10000))
print(math.pi)
Output:
3.28125
3.148427801913721
3.141592653589793
Remarks:
You only want the odd primes, so you can start with a list of odd numbers.
j can start with 3 and increment in steps of 2. In fact, j can start at i because all the multiples of i smaller than i*i are already removed earlier.
In general it is very bad practise to remove elements from the list over which you are iterating. See e.g. this post. Internally, Python uses an index into the list over which it iterates. Coincidently, this is not a problem in this specific case, because only numbers larger than the current are removed.
Also, removing elements from a very long list is very slow, as each time the complete list needs to be moved to fill the gap. Therefore, it is better to work with two separate lists.
You didn't calculate the resulting product, nor did you return it.
As you notice, this formula converges very slowly.
As mentioned in the comments, the previous version interpreted n as the limit for highest prime, while in fact n should be the number of primes. I adapted the code to rectify that. In the above version with a crude limit; the version below tries a tighter approximation for the limit.
Here is a reworked version, without removing from the list you're iterating. Instead of removing elements, it just marks them. This is much faster, so a larger n can be used in a reasonable time:
import math
def pi_euler_v3(n):
if n < 3:
lim = 6
else:
lim = n*n
while lim / math.log(lim) / 2 > n:
lim //= 2
print(n, lim)
numerator = list(range(3, lim, 2))
odd_primes = []
for i in numerator:
if i is not None:
odd_primes.append(i)
if len(odd_primes) >= n:
break
j = i
while i * j < lim:
numerator[(i*j-3) // 2] = None
j += 2
if len(odd_primes) != n:
print(f"Wrong limit calculation, only {len(odd_primes)} primes instead of {n}")
euler_product = 1
for k in odd_primes:
denominator = k + 1 if k % 4 == 3 else k - 1
euler_product *= k / denominator
return euler_product * 4
print(pi_euler_v2(100000))
print(math.pi)
Output:
3.141752253548891
3.141592653589793
In term = numerator / denominator you are dividing a list by a number, which doesn't make sense. Divide k by the denominator in the loop in order to use the numerator element for each of the equation's factors one by one. Then you could multiply them repeatedly to the term term *= i / denominator, which you initialize in the beginning as term = 1.
Another issue is the first loop, which won't give you the first n prime numbers. For example, for n=3, list(range(2 , n)) = [2]. Therefore, the only prime you will get is 2.

For a user input n, and 1<=i<j<=n, find the number of pairs where i*i*i=j*j using python

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)

How to obtain the result of n(n-1)(n-2) / 6

In my Python book, the question asks to prove the value of x after running the following code:
x = 0
for i in range(n):
for j in range(i+1, n):
for k in range(j+1, n):
x += 1
What I could see is that:
i = 0; j=1; k=2: from 2 to n, x+=1, (n-2) times 1
i = 1; j=2; k=3: from 3 to n, x+=1, (n-3) times 1
...
i=n-3; j=n-2; k=n-1: from n-1 to n, x+=1, just 1
i=n-2; j=n-1; k=n doesn't add 1
So it seems that the x is the sum of series of (n-2) + (n-3) + ... + 1?
I am not sure how to get to the answer of n(n-1)(n-2)/6.
One way to view this is that you have n values and three nested loops which are constructed to have non-overlapping ranges. Thus the number of iterations possible is equal to the number of ways to choose three unique values from n items, or n choose 3 = n!/(3!(n-3)!) = n(n-1)(n-2)/3*2*1 = n(n-1)(n-2)/6.
Just write the for loops as a sigma: S = sum_{i=1}^n sum_{j=i+1}^n sum_{k = j + 1}^n (1).
Try to expand the sum from inner to outer:
S = sum_{i=1}^n sum_{j=i+1}^n (n - j) = sum_{i=1}^n n(n-i) - ((i+1) + (i+2) + ... + n) = sum_{i=1}^n n(n-i) - ( 1+2+...+n - (1+2+...+i)) = sum_{i=1}^n n(n-i) -(n(n+1)/2 - i(i+1)/2) = sum_{i=1}^n n(n+1)/2 + i(i+1)/2 - n*i = n^2(n+1)/2 + sum_{i=1}^n (i^2/2 + i/2 - n*i).
If open this sum and simplify it (it is straightforward) you will get S = n(n-1)(n-2)/6.

What's the time complexity of this method to find the number of inversions in an array (python)?

inv=0
for j in range(n):
inv=inv+ sum((x<arr[j]) for x in arr[j:] )
For every element I am checking the number of elements smaller than it occurring after it in the array.(arr[j : ])
It is O(n2). Here is how you can compute this:
for the 1st element, you need to compare with the next n-1 elements.
for the 2nd element, you need to compare with the next n-2 elements.
...
for the nth element, you need to compare with the next 0 elements.
Therefore, in total you are making (n-1) + (n-2) + ... + 1 + 0 = n(n-1) / 2 comparisons, which is quadratic in n.
More efficient approaches do exist. For example, by using a divide and conquer based strategy, you can count them in O(n log(n)). See this nice link!
inv=0
for j in range(n):
inv=inv+ sum((x<arr[j]) for x in arr[j:] )
Let's break this code into three parts
1: inv = 0
This will take contant time operation sat T1
2: for j in range(n):
here we are running a loop for variable n
total time required now is T1 + N * f(a) here f(a) is the time taken by the body of loop. For simplicity we can remove constant factor. So complexity is N * f(a)
Now here comes the tricky part. What is f(a)
3: inv = inv + sum((x<arr[j]) for x in arr[j:] )
concentrate on sum((x < arr[j] for x in arr[j:])
sum will add all the values that are below arr[j] in
loop for x in arr[j:]
so you are left with f(a) as N, N - 1, N - 2 up to N - N
Combining this all together you get N * (N + N - 1 + N - 2 + ... + N - N) which is (N * N - 1) / 2 that is O(N^2)
Hope you get it.

Categories