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

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.

Related

Python: calculate (1/1) + (1 + 2) / 2 + ... + (1 + 2 + ... + n) / n [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 10 months ago.
Improve this question
The use of for loops is not allowed. This program is designed to calculate values up to number 'n' which is a value entered by the user. Help on this would be appreciated. A photo of the problem and my code so far is listed below:
import math
counterN = 0 #Numerator
counterD = 0 #Denominator
divNumber = 0 #Numerator/Denominator
nValue = 0 #Variable to add numberator values to
dValue = 0 #Variable to add denominaor values to
#Prompts user for a
print("Please enter a value for calculation: ")
number = int(input())
if (number <= 0):
print("Invalid input given.")
#Adds the numerator up to number entered by user
while (counterN <= number):
counterN = counterN + 1
nValue += counterN
#Denominator calculation
counterD = counterD + 1
dValue += counterD
divNumber = nValue / dValue
divNumber += divNumber
#Outputs value to user
print("The result is" , divNumber)
print(counterN, nValue)
You can use recursion for such problems. I've written a recursive solution for you which I found very intuitive-
global SUM
SUM = 0
def fracSUMCalc(n):
if n == 1:
return 1
SUM = fracSUMCalc(n-1) + (sum(range(1, n+1)) / n)
return SUM
print(fracSUMCalc(n=998))
This prints out 249749.5 which is the answer to the sum of your series till n=998. You can vary n as per your need.
Please note that this solution will work fine on any standard modern day laptop till n=998. For n>998, you'd either have to increase your machine's recursion depth limit or use a different approach to develop a more efficient program.
There is a solution that just uses no loops or recursion at all, just maths
def frac_series_sum(n):
return n + sum(range(n)) * 0.5
print(frac_series_sum(1)) # 1.0
print(frac_series_sum(5)) # 10.0
print(frac_series_sum(100)) # 2575.0
It can be shown (see below) that your sum is equal to
for any natural number n.
Thus, this function calculates the sum you want. It does not involve any recursion, for loops or any kind of iteration (it is O(1)):
def my_calc(n):
"Returns 1/1 + (1 + 2)/2 + ... + (1 + 2 + ... + n)/n"
return 0.25 * n * (n + 3)
This is as efficient as it gets.
If you are not allowed to use the solution above and you need to use a while loop:
def my_inefficient_calc(n):
"Returns 1/1 + (1 + 2)/2 + ... + (1 + 2 + ... + n)/n"
result = 0
i = 1
while (i <= n):
result += (sum(range(1, i + 1))) / i
i += 1
return result
If you are not allowed to use the built-in sum function, you can calculate the sum using a nested while loop:
def even_less_efficient(n):
"Returns 1/1 + (1 + 2)/2 + ... + (1 + 2 + ... + n)/n"
result = 0
i = 1
while (i <= n):
inner_sum = 0
k = 1
while (k <= i):
inner_sum += k
k += 1
result += inner_sum / i
i += 1
return result
i is a loop variable (counter) for the outer loop. It ranges from i = 1 up to n.
k is a loop variable (counter) for the inner loop. It ranges from k = 1 up to i.
The inner loop is responsible for calculating the sum in the numerator for each term. This sum is stored in inner_sum.
Once the sum is calculated for a given i (i.e. once we are done with the inner loop), we divide this sum by i to get one of the terms in the mathematical expression.
The outer loop is responsible for summing all of the terms from i = 1 up to n.
Intuitive Proof
How did I arrive at this?
You want a program that calculates the following sum:
This is an elegant solution that has stuck with me for a long time that I will never forget. I once learned in real analysis of a famous mathematician who at the age of 5 (if I remember correctly) reasoned that the sum of i from i = 1 up to k is:
He did so by writing out the sum twice, but the second in reverse order:
(sum of i from i = 1 to k) = 1 + 2 + ... + (k - 1) + k
(sum of i from i = 1 to k) = k + (k - 1) + ... + 2 + 1
----------------------------------------------------------
(k+1)+ (k+1) +... + (k+1) + (k+1) # k terms
He noticed that each sum has k numbers and the sum of each column is equal to k + 1. So, if you add the two sums, you get
2 * (sum of i from i = 1 to k) = k * (k + 1)
Thus
(sum of i from i = 1 to k) = (k * (k + 1)) / 2
which is the same as the result in the second image above.
Substitution of this result into the left-hand-side of the expression in the first image:
Now apply the result that we derived again to the last expression above:
Thus
or
0.25 * n * (n + 3)
Note: A formal proof of the above result would be a proof by induction to show it is true for any natural number n. This proof by induction part is the easy part. I have omitted such a proof as the above should be obvious to anyone that sees it.
Bro, I just did easier
counterN = 1 #Numerator
result = []
#Prompts user for a
print("Please enter a value for calculation: ")
number = int(input())
if (number <= 0):
print("Invalid input given.")
#Adds the numerator up to number entered by user
while (counterN <= number):
numerator = sum(range(counterN+1))
denominator = counterN
result.append(numerator / denominator)
#solucion
counterN += 1
#Outputs value to user
print("The result is" , sum(result))

Sum of 1+3+5...+n until the sum exceeds 100

Then the sum and the last added number and the number of numbers added must be printed.
I am currently stuck, I managed to get the sum part working. The last added number output is printed "23" but should be "21". And lastly, how can I print the number of numbers added?
Output goal: 121, 21, 11
Here is my code:
n = int()
sum = 0
k = 1
while sum <= 100:
if k%2==1:
sum = sum + k
k = k + 2
print('Sum is:', sum)
print("last number:", k)
Edit: Would like to thank everyone for their help and answers!
Note, that (you can prove it by induction)
1 + 3 + 5 + ... + 2 * n - 1 == n**2
<----- n items ----->
So far so good in order to get n all you have to do is to compute square root:
n = sqrt(sum)
in case of 100 we can find n when sum reach 100 as
n = sqrt(100) == 10
So when n == 10 then sum == 100, when n = 11 (last item is 2 * n - 1 == 2 * 11 - 1 == 21) the sum exceeds 100: it will be
n*n == 11 ** 2 == 121
In general case
n = floor(sqrt(sum)) + 1
Code:
def solve(s):
n = round(s ** 0.5 - 0.5) + 1;
print ('Number of numbers added: ', n);
print ('Last number: ', 2 * n - 1)
print ('Sum of numbers: ', n * n)
solve(100)
We have no need in loops here and can have O(1) time and space complexity solution (please, fiddle)
More demos:
test : count : last : sum
-------------------------
99 : 10 : 19 : 100
100 : 11 : 21 : 121
101 : 11 : 21 : 121
Change your while loop so that you test and break before the top:
k=1
acc=0
while True:
if acc+k>100:
break
else:
acc+=k
k+=2
>>> k
21
>>> acc
100
And if you want the accumulator to be 121 just add k before you break:
k=1
acc=0
while True:
if acc+k>100:
acc+=k
break
else:
acc+=k
k+=2
If you have the curiosity to try a few partial sums, you immediately recognize the sequence of perfect squares. Hence, there are 11 terms and the last number is 21.
print(121, 21, 11)
More seriously:
i, s= 1, 1
while s <= 100:
i+= 2
s+= i
print(s, i, (i + 1) // 2)
Instead of
k = k + 2
say
if (sum <= 100):
k = k +2
...because that is, after all, the circumstance under which you want to add 2.
To also count the numbers, have another counter, perhasp howManyNumbers, which starts and 0 and you add 1 every time you add a number.
Just Simply Change you code to,
n = int()
sum = 0
k = 1
cnt = 0
while sum <= 100:
if k%2==1:
sum = sum + k
k = k + 2
cnt+=1
print('Sum is:', sum)
print("last number:", k-2)
print('Number of Numbers Added:', cnt)
Here, is the reason,
the counter should be starting from 0 and the answer of the last printed number should be k-2 because when the sum exceeds 100 it'll also increment the value of k by 2 and after that the loop will be falls in false condition.
You can even solve it for the general case:
def sum_n(n, k=3, s =1):
if s + k > n:
print('Sum is', s + k)
print('Last number', k)
return
sum_n(n, k + 2, s + k)
sum_n(int(input()))
You can do the following:
from itertools import count
total = 0
for i, num in enumerate(count(1, step=2)):
total += num
if total > 100:
break
print('Sum is:', total)
print("last number:", 2*i + 1)
To avoid the update on k, you can also use the follwoing idiom
while True:
total += k # do not shadow built-in sum
if total > 100:
break
Or in Python >= 3.8:
while (total := total + k) <= 100:
k += 2
Based on your code, this would achieve your goal:
n = 0
summed = 0
k = 1
while summed <= 100:
n += 1
summed = summed + k
if summed <= 100:
k = k + 2
print(f"Sum is: {summed}")
print(f"Last number: {k}")
print(f"Loop count: {n}")
This will solve your problem without changing your code too much:
n = int()
counter_sum = 0
counter = 0
k = 1
while counter_sum <= 100:
k+= 2
counter_sum =counter_sum+ k
counter+=1
print('Sum is:', counter_sum)
print("last number:", k)
print("number of numbers added:", counter)
You don't need a loop for this. The sum of 1...n with step size k is given by
s = ((n - 1) / k + 1) * (n + 1) / k
You can simplify this into a standard quadratic
s = (n**2 - k * n + k - 1) / k**2
To find integer solution for s >= x, solve s = x and take the ceiling of the result. Apply the quadratic formula to
n**2 - k * n + k - 1 = k**2 * x
The result is
n = 0.5 * (k + sqrt(k**2 - 4 * (k - k**2 * x - 1)))
For k = 2, x = 100 you get:
>>> from math import ceil, sqrt
>>> k = 2
>>> x = 100
>>> n = 0.5 * (k + sqrt(k**2 - 4 * (k - k**2 * x - 1)))
>>> ceil(n)
21
The only complication arises when you get n == ceil(n), since you actually want s > x. In that case, you can test:
c = ceil(n)
if n == c:
c += 1

Optimising sequence code after Time limit exceeded error

FIND THE SEQUENCE SUM
i = 5
j = 9
K = 6
sum all the values from i to j and back to K: 5 + 6 + 7 + 8 + 9 + 8 + 7 + 6
My answer is:
def sequence_sum(i,j,k):
sum = 0
for i in range(i,j+1):
sum += i
for m in range(j-1,k-1,-1):
sum += m
return sum
However, this solution is correct I received a 9/12 out of the test cases and was given an error message that stated that the time limit was exceeded, I was allowed 10 seconds and the message read " Your code did not execute within the time limits. Please optimise your code."
Can I please get some help with this as I don't understand what I am suppose to do here?
Notice the sum from 5 to 9 is the same as:
(5+0) + (5+1) + (5+2) + (5+3) + (5+4)
If we extract 5, we have: 5*(9-5+1) + (sum from 1 to (9-5)).
To get a general formula:
sum(a,b) = (b-a+1) * a + (b-a)*(b-a+1)/2
The second formula is the sum of all natural numbers up to b-a.
so create the following function:
def my_sum(a,b):
return (b-a+1) * a + (b-a)*(b-a+1)/2
thus the sequence_sum(i,j,k):
def sequence_sum(i,j,k):
return my_sum(i,j) + my_sum(k,j-1)
You can simply use range() function returning an iterable + sum function:
sum's time complexity is O(n) and the range function returns a lazy iterable. That is also O(n) operation.
The return statement returns only the reference of the list so it's time complexity is O(1)
return sum(range(i,j))+sum(range(j,k-1,-1))
the sum from 1, to i is i * (i + 1) / 2 let's call it s(i).
and f(i, j) is the sum from i to j.
f(i, j) = i + (i + 1) + ... + j = 1 + 2 + ... + j - (1 + 2 + ... + (i - 1))
so f(i, j) = s(j) - s(i-1)
the sum from j back to k (but we have to eliminate j because already counted), is the same as the sum from k to j-1 which is f(k, j-1) = s(j-1) - s(k-1)
The total answer is: s(j) - s(i-1) + s(j-1) - s(k-1).
The complexity of sfunction is O(1) so this should pass the test cases
Simpler formula for a range sum, including its derivation:
5 + 6 + 7 + 8
= (write all numbers twice and halve the sum)
(5 + 6 + 7 + 8 +
8 + 7 + 6 + 5) / 2
= (sum each vertical pair)
(13 + 13 + 13 + 13) / 2
=
4 * 13 / 2
=
(8 - 5 + 1) * (5 + 8) / 2
So in general for the sum from i to j: (j - i + 1) * (i + j) / 2
TLE is the case here. So you need to optimize your code.
For that, we can have two approaches.
1st approach: Simple looping
Apply a loop from i to j. And check if the current number is greater than or equal to k. If it is then add 2 times of current number. Else keep adding it once.
for n in range(i,j+1):
if n>=k:
sum+= 2*n
else:
sum+= n
2nd approach: Maths
We know that sum of first n integers is n*(n+1)/2
So what you can do is find sum till j, remove the sum till i (i excluded) from it.
Similarly, for k, find the sum till j and remove the sum till k (k excluded) from it.
Add remaining sums of both minus j as it will get considered twice.
i.e.
sum1 = j*(j+1)/2 - i*i(i-1)/2
sum2 = j*(j+1)/2 - k*(k-1)/2
ans = sum1+sum2 - j;

Count all sub-arrays having sum divisible by k

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...

find total data in N*N matrix

a matrix consists of N × N blocks .the block number is equal to the sum of the row number and the column number. each block consists of data, and data is equal to difference of sum of even and odd digits of the block number . calculate total data of n*n blocks
i/o format
lets n = 4
so
matrix will be
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8
so total data = 2+3+4+5+3+4+5+6+4+5+6+7+5+6+7+8=80
if number of block is 4256 in any case then data in it will be abs(diff(sum(even digits)- sum(odd digits))) which is abs((4+2+6)-(5))= 7
my naive attempt
n = int(raw_input())
sum1=0
sum2=0
for i in range(1,n+1):
for j in range(1,n+1):
sum1 = i+j
diffsum = diff(sum1)
sum2 = sum2+diffsum
print sum2
again optimized attempt
def diff(sum1):
sum1 = str(sum1)
m = sum([int(i) for i in sum1 if int(i) % 2 == 0])
f = sum([int(i) for i in sum1 if int(i) % 2 != 0])
return abs(m - f)
n = int(raw_input())
sum1 = 0
k = 1
# t1 = time.time()
p = 2 * n
for i in range(2, n + 2):
diffsum = diff(i)
diffsum1 = diff(p)
sum1 = sum1 + (diffsum * k)
sum1 = sum1 + (diffsum1 * k)
p = p - 1
k = k + 1
sum1 = sum1 - (diff(n + 1) * n)
print sum1
diff is common function in both case. i need more optmization with the following algorithm
Your optimised approach calculates the digit sum only once for each number, so at first sight, there isn't anything to be gained from memoisation.
You can improve the performance of your diff function by merging the two loops into one and use a dictionary to look up whether you add or subtract a digit:
value = dict(zip("0123456789", (0, -1, 2, -3, 4,-5, 6,-7, 8,-9)))
def diff2(s):
s = str(s)
return abs(sum([value[i] for i in s]))
This will require a conversion to string. You can get a bit faster (but not much) by calculating the digits by hand:
dvalue = [0, -1, 2, -3, 4,-5, 6,-7, 8,-9]
def diff(s):
t = 0
while s:
t += dvalue[s % 10]
s //= 10
return abs(t)
Finally, you can make use of the fact that you calculate all digit sums from 2 up to 2·n sequentially. Store the digits of the current number in an array, then implement an odometer-like counter. When you increment that counter, keep track of the odd and even digit sums. In 9 of 10 cases, you just have to adjust the last digit by removing its value from the respective sum and by adding the next digit to the other sum.
Here's a program that does this. The function next increments the counter and keeps the digit sums of even and odd numbers in sums[0] and sums[1]. The main program is basically the same as yours, except that the loop has been split into two: One where k increases and one where it decreases.
even = set(range(0, 10, 2))
def next(num, sums):
o = num[0]
if o in even:
sums[0] -= o
sums[1] += o + 1
else:
sums[0] += o + 1
sums[1] -= o
num[0] += 1
i = 0
while num[i] == 10:
sums[0] -= 10
num[i] = 0
i += 1
o = num[i]
if o in even:
sums[0] -= o
sums[1] += o + 1
else:
sums[0] += o + 1
sums[1] -= o
num[i] += 1
n = int(raw_input())
total = 0
m = len(str(2 * n + 1))
num = [0] * m
num[0] = 2
sums = [2, 0]
k = 1
for i in range(2, n + 2):
total += abs(sums[0] - sums[1]) * k
k += 1
next(num, sums)
k = n
for i in range(n + 2, 2*n + 1):
k -= 1
total += abs(sums[0] - sums[1]) * k
next(num, sums)
print total
I've said above that memoisation isn't useful for this approach. That's not true. You could store the even and odd digit sums of number i and make use of it when calculating the numbers 10 * i to 10 * i + 9. When you call diff in order of increasing i, you will have access to the stored sums of i // 10.
This isn't significantly faster than the odometer approach, but the implementation is clearer at the cost of additional memory. (Preallocated arrays work better than dictionaries for big n. You don't need to reserve space for numbers above (2*n + 11) / 10.)
def diff(s):
d = s % 10
e = ememo[s / 10]
o = omemo[s / 10]
if d in even:
e += d
else:
o += d
if s < smax:
ememo[s] = e
omemo[s] = o
return e, o
n = int(raw_input())
total = 0
even = set(range(0, 10, 2))
smax = (2*n + 11) / 10
omemo = smax * [0]
ememo = smax * [0]
omemo[1] = 1
k = 1
for i in range(2, n + 2):
e, o = diff(i)
total += abs(e - o) * k
k += 1
k = n
for i in range(n + 2, 2*n + 1):
k -= 1
e, o = diff(i)
total += abs(e - o) * k
print total
This could be made even faster if one could find a closed formula for the digit sums, but I think that the absolute function prevents such a solution.

Categories