Given: Two positive integers a and b (a
Return: The sum of all odd integers from a through b, inclusively.
#My code:
a = 100
b = 200
for i in range(a,b):
if i%2 == 1:
print i
At the moment it's just showing a drop down list of all the odd integers. I do not know how to affix a "range" to this properly, if need be. How can I add on to my code above to get the sum of all the odd integers?
Thanks
Sum all the numbers between a and b if odd.
sum(i for i in xrange(a, b) if i%2)
A rather quick way to do it would be:
result = 0
for i in range(a,b+1):
if i%2 == 1:
result += i
print result
There are a bunch of ways to do this. If you think about the math, though, it's a lot like Gauss's old problem. Gauss was asked to add the numbers between 1 and 100, and he realized that each pair of high and low values summed to 101 (100 + 1, 99 + 2, 98 + 3…)
high = b
low = a
So we have to multiply some number of b + a values. How many are there? For all the integers, that's just
num_pairs = (high-low) // 2
Then we multiply that number by high + low to get the answer:
result = (high + low) * num_pairs
But you only want every other ones, so we divide by two again:
result //= 2
Totally:
def sumrange(low, high, step):
num_pairs = (high - low) // 2
result = (high + low) * num_pairs
return result // step
or sumrange = lambda low, high, step: (high - low) * (high + low) // (2 * step)
Now this still isn't quite an answer to your question, because it needs to be offset depending on whether your low value is odd, and whether your high value is included or excluded. But I will leave that as an exercise.
Making this a CW answer so someone can edit if my math is messy.
Some mathematical tricks can solve your problem much efficiently.
For example, sum of first n odd numbers = n*n square(n)
So you can use for
Sum of odd numbers [m,n] = n*n - (m-2)*(m-2) where m!=1 and m and n are odds
One more useful analysis is, AP (arithmetic progression)
Formula : (n/2)*(a+l) where n= no. of elements, a = first term, l= last term
Here,
a = m [if m is odd]
a = m+1 [if m is even]
l = n [if n is odd]
l = n-1 [if n is even]
n = ( ( l - a ) / 2 ) + 1
By applying in code, you can easily get the answer...
And the numpy version of the solution:
import numpy as np
a = 100
b = 200
r = np.linspace(a,b-1,b-a)
r = np.sum(np.mod(r,2)*r)
print(r)
Related
I am doing an assessment that is asking by the given "n" as input which is a length of a stick; how many triangles can you make? (3 < n < 1,000,000)
For example:
input: N=8
output: 1
explanation:
(3,3,2)
input: N=12
output: 3
explanation:
(4,4,4) (4,5,3) (5,5,2)
Now the codes I wrote are returning 33 % accuracy as the web assessment is throwing time limit error.
ans = 0
n = int(input())
for a in range(1, n + 1):
for b in range(a, n - a + 1):
c = n - a - b
if a + b > c >= b:
ans += 1
print(ans)
code b:
ans = 0
n = int(input())
for i in range(1,n):
for j in range(i,n):
for c in range(j,n):
if(i+j+c==n and i+j>c):
ans+=1
print(ans)
How can this be made faster?
This is an intuitive O(n) algorithm I came up with:
def main():
n = int(input())
if n < 3:
print(0)
return
ans = n % 2
for a in range(2, n//2+1):
diff = n - a
if diff // 2 < a:
break
if diff % 2 == 0:
b = diff // 2
else:
b = diff // 2 + 1
b = max(b - a // 2, a)
c = n - b - a
if abs(b - c) >= a:
b += 1
c -= 1
ans += abs(b-c)//2 + 1
print(ans)
main()
I find the upper bound and lower bound for b and c and count the values in that range.
I thought of a completely different way to do it:
We take the smallest side and call it a. It can never be more than n/3, otherwise a different side would be the smallest.
We try to figure out what is the next smallest side (b):
We see what's left after reducing our a.
We divide it by 2 in order to find the middle where we'll start advancing from
We'll see how far we can get before the difference between the lengths is a (or the difference from the middle is a/2) as that's the minimum b side length that is possible and satisfies a+b>c. Basically, the second smallest side is a/2 less than the middle.
The smallest side is the maximum between our calculation or a, in caseb==a. b can never be lower than a as it violates our first rule that a is the smallest.
We figure out the difference from the middle and the smallest side. That's how many possible solutions we have for the other 2 sides.
Add everything together for every a and that's our solution.
The floor, ceil and % are fixes for when a is odd, the middle is .5, or +1 in case b+c is even, cause b==c is then possible.
Code:
import math
n = int(input("Enter a number: "))
total = 0
# a is the shortest side
for a in range(1, (n//3)+1):
length_left = n-a
middle_number = length_left/2
# Shortest potential side b where the distance between b and c is smaller than a (c-b < a)
b = middle_number-(math.ceil(a/2)-1)-((length_left % 2)/2)
# We calculate how far it is from the middle
max_distance_from_middle = middle_number - max(b, a)
# Add another 1 if the length is even, in case b==c
adding = math.floor(max_distance_from_middle) + (1 if length_left % 2 == 0 else 0)
total += adding
print(total)
Or in an ugly one-liner:
n = int(input("Enter a number: "))
print(sum(math.floor((n-a)/2 - max((n-a)/2 - math.ceil(a/2) + 1 - (((n-a) % 2)/2), a)) + 1 - ((n-a) % 2) for a in range(1, (n//3)+1)))
Alcuin's sequence expansion: O(1)
Alcuin's sequence [See: https://en.wikipedia.org/wiki/Alcuin%27s_sequence] is a series expansion of the polynomial below, where the nth coefficient corresponds to the nth answer, that is, the maximum amount of unique integer triangles with perimeter n.
The algorithmic implementation of this is simply a formula. The Online Encyclopaedia of Integer Sequences (OEIS) provides many formulas that achieve this, the simplest of which is:
round(n^2 / 48) (Even)
round((n+3)^2 / 48) (Odd)
[See: https://oeis.org/A005044]
This evidently has a constant time complexity, given that the only functions required are modulo 2, integer squared and round, each of which are constant time (under certain definitions).
Implementation
Expanded:
def triangles(n):
if n % 2 == 0:
return round(n ** 2 / 48)
else:
return round((n + 3) ** 2 / 48)
1-Liner:
def triangles(n): return round(n ** 2 / 48) if n%2==0 else round((n + 3) ** 2 / 48)
Or even:
def triangles(n): return round((n + 3 * n%2) ** 2 / 48)
Extra
No imports are needed.
As the OP questioned, why do we divide by 48? While I can't answer that explicitly, let's get an intuitive understanding. We are squaring numbers, so it is evidently going to expand greatly. By the time we get to 5, that would give 64 (8^2). So, there must be a constant (albeit a reciprocal) to restrict the growth of the parabola, thus the / 48.
When we graph the OP's method, it gives an alternating parabola. This explains why there is a back-and-forth with the +3 and +0.
https://mathworld.wolfram.com/AlcuinsSequence.html
import math
n = int(input())
print(round(n ** 2 / 48)) if n % 2 == 0 else print(round((n + 3)** 2 / 48))
I am trying to use hash table to solve this question. The question description is: "Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array."
My approach so far is to import the dictionary and use it as a list. Then I am enumerating through the integer array that is given to me. So, for now, nums=[0,1,2,3,4,6]. I have to return number 5 as the missing number. After enumerating, I am trying to go over the items of the dictionary and see which number is missing. If the length of the v is none inside the index, then I will return this line int((((length * (length+1))/2) - sums))
from collections import defaultdict
class Solution(object):
def missingNumber(self, nums):
d = defaultdict(list)
length = len(nums)
sums = sum(nums)
for numbers, index in enumerate(nums):
d[index].append(numbers)
for k,v in d.items():
if len(v) == 0 :
return int((((length * (length+1))/2) - sums))
I am confused about how to show the if statement. Like how from the list it can be recognized that 5 is missing. Also, if there are more than 2 numbers are missing, then what approach will be the best to take? As if the example was: nums = [0,1,2,6,8]
Pardon for not having enough knowledge. I am just a beginner trying to practice questions everyday.
If you can use sum then no loop is required:
sum1 = sum(nums)
sum2 = sum(range(n))
missing_num = sum2 - sum1
Can we assume more than simply that the list contains indices with one missing? If, for example, we know that the list is sorted, we can get a logarithmic time solution using a binary search.
def bsearch(x: list[int]) -> int:
"""Return missing index in a sorted list."""
low, high = 0, len(x)
while low < high:
mid = (low + high) // 2
if x[mid] == mid:
# lower half have matching indices; explore upper
low = mid + 1
else:
# mid's value is too high; lower half has missing index
high = mid
return low
It exploits that below the missing value, i == x[i], but after the missing value, the array values are off by one, i == x[i] + 1. By testing the middle point in an interval, we can work out whether the missing element is to the left or right, and by doing this, we get a O(log n) solution.
If the elements are not sorted, you can of course sort them first and then do a binary search. A comparison sort would take O(n log n) and a bucket/radix sort O(n). There is nothing much good to say about first sorting the elements, then, as others have suggested, you can get the answer in O(n) without sorting.
I can try to explain that solution in a little more detail.
The sum of all numbers up to n is n * (n+1) // 2.
sum(range(n+1)) == n * (n+1) // 2
So
n*(n+1)//2 = 0 + 1 + 2 + ... + i-1 + i + i+1 + ... + n
The sum of the numbers that actually appear is sum(x), so if i is missing:
sum(x) = 0 + 1 + 2 + ... + i-1 + 0 + i+1 +... + n
Subtract the latter from the former and you get the missing value:
n*(n+1)//2: 0 + 1 + 2 + ... + i-1 + i + i+1 + ... + n
- sum(x): -(0 + 1 + 2 + ... + i-1 + 0 + i+1 + ... + n)
= 0 + 0 + 0 + ... + 0 + i + 0 + ... + 0
= i
so the solution is
def general_solution(x: list[int]) -> int:
return len(x) * (len(x) + 1) // 2 - sum(x)
Computing len(x) * (len(x) + 1) // 2 takes constant time, but sum(x) takes O(n), so the total running time is O(n).
If your array is sorted, the binary search approach will be much faster, but if the array is not sorted, a linear time solution isn't bad. There will certainly not be need for anything slower than O(n).
Hey this is my solution.
Subtract the sum of the elements in the list from the sum of the consecutive numbers you have (n * (n+1) / 2) and you will get the result.
class Solution:
def MissingNumber(self, nums):
l = len(nums)
total = l * (l + 1) / 2
sum_giv_list = sum(nums)
return total - sum_giv_list
You don't need a dict, you can do it in a for loop
for i in range(n)
if i not in nums:
return i
if you are not told what n is then you can do something like:
for i in range(nums[-1])
if i not in nums:
return i
if there are a possibility of more than one number missing then you can add them to a list before returning them
missing_nums = []
for i in range(nums[-1]):
if i not in nums:
missing_nums.append(i)
return missing_nums
n = 5
cube = n**3
def get_sum(n):
a1 = n * (n - 1) + 1
for i in range(a1, cube, 2):
print(i, end='+')
print(f'{get_sum(n)}')
print(cube)
I have output:
21+23+25+27+29+31+33+35+37+39+41+43+45+47+49+51+53+55+57+59+61+63+65+67+69+71+73+75+77+79+81+83+85+87+89+91+93+95+97+99+101+103+105+107+109+111+113+115+117+119+121+123+None
125
How can I get a range till 29 so the sum of these numbers will be equal to cube in Python?
For example, 21+23+25+27+29 = 5^3
first, no need to write print(f'{get_sum(n)}') since your function doesn't return anything except None which you can see in your output, get_sum(n) is enough.
since you are always looping n times, you can simplify your condition, in my solution I used a while loop with a sum variable to keep tabs with the current sum of numbers.
you can apply the same logic with a for loop of course, this is just my implementation.
def get_sum(n):
a1 = n * (n - 1) + 1
sum = a1
while sum < cube:
print(a1, end='+')
a1+=2
sum+=a1
print(a1, end='=')
n = 5
cube = n**3
get_sum(n)
print(cube)
output:
21+23+25+27+29=125
Inefficient approach:
Keep a variable that tracks the current sum to check if we need to break the loop or not (as mentioned in the other answers).
Efficient Approach:
n^3 can be expressed as a sum of n odd integers, which are symmetric about n^2. Examples:
3^3 = 7+9+11 (symmetric about 9)
4^3 = 13+15+17+19 (symmetric about 16)
5^3 = 21+23+25+27+29 (symmetric about 25)
Use this approach to get a simpler algorithm
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.
Examples,
1.Input=4
Output=111
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
------------------------
sum = 111(output)
1.Input=5
Output=237
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
5 = 1³ + 5³(divisors of 5)
-----------------------------
sum = 237 (output)
x=int(raw_input().strip())
tot=0
for i in range(1,x+1):
for j in range(1,i+1):
if(i%j==0):
tot+=j**3
print tot
Using this code I can find the answer for small number less than one million.
But I want to find the answer for very large numbers. Is there any algorithm
for how to solve it easily for large numbers?
Offhand I don't see a slick way to make this truly efficient, but it's easy to make it a whole lot faster. If you view your examples as matrices, you're summing them a row at a time. This requires, for each i, finding all the divisors of i and summing their cubes. In all, this requires a number of operations proportional to x**2.
You can easily cut that to a number of operations proportional to x, by summing the matrix by columns instead. Given an integer j, how many integers in 1..x are divisible by j? That's easy: there are x//j multiples of j in the range, so divisor j contributes j**3 * (x // j) to the grand total.
def better(x):
return sum(j**3 * (x // j) for j in range(1, x+1))
That runs much faster, but still takes time proportional to x.
There are lower-level tricks you can play to speed that in turn by constant factors, but they still take O(x) time overall. For example, note that x // j == 1 for all j such that x // 2 < j <= x. So about half the terms in the sum can be skipped, replaced by closed-form expressions for a sum of consecutive cubes:
def sum3(x):
"""Return sum(i**3 for i in range(1, x+1))"""
return (x * (x+1) // 2)**2
def better2(x):
result = sum(j**3 * (x // j) for j in range(1, x//2 + 1))
result += sum3(x) - sum3(x//2)
return result
better2() is about twice as fast as better(), but to get faster than O(x) would require deeper insight.
Quicker
Thinking about this in spare moments, I still don't have a truly clever idea. But the last idea I gave can be carried to a logical conclusion: don't just group together divisors with only one multiple in range, but also those with two multiples in range, and three, and four, and ... That leads to better3() below, which does a number of operations roughly proportional to the square root of x:
def better3(x):
result = 0
for i in range(1, x+1):
q1 = x // i
# value i has q1 multiples in range
result += i**3 * q1
# which values have i multiples?
q2 = x // (i+1) + 1
assert x // q1 == i == x // q2
if i < q2:
result += i * (sum3(q1) - sum3(q2 - 1))
if i+1 >= q2: # this becomes true when i reaches roughly sqrt(x)
break
return result
Of course O(sqrt(x)) is an enormous improvement over the original O(x**2), but for very large arguments it's still impractical. For example better3(10**6) appears to complete instantly, but better3(10**12) takes a few seconds, and better3(10**16) is time for a coffee break ;-)
Note: I'm using Python 3. If you're using Python 2, use xrange() instead of range().
One more
better4() has the same O(sqrt(x)) time behavior as better3(), but does the summations in a different order that allows for simpler code and fewer calls to sum3(). For "large" arguments, it's about 50% faster than better3() on my box.
def better4(x):
result = 0
for i in range(1, x+1):
d = x // i
if d >= i:
# d is the largest divisor that appears `i` times, and
# all divisors less than `d` also appear at least that
# often. Account for one occurence of each.
result += sum3(d)
else:
i -= 1
lastd = x // i
# We already accounted for i occurrences of all divisors
# < lastd, and all occurrences of divisors >= lastd.
# Account for the rest.
result += sum(j**3 * (x // j - i)
for j in range(1, lastd))
break
return result
It may be possible to do better by extending the algorithm in "A Successive Approximation Algorithm for Computing the Divisor Summatory Function". That takes O(cube_root(x)) time for the possibly simpler problem of summing the number of divisors. But it's much more involved, and I don't care enough about this problem to pursue it myself ;-)
Subtlety
There's a subtlety in the math that's easy to miss, so I'll spell it out, but only as it pertains to better4().
After d = x // i, the comment claims that d is the largest divisor that appears i times. But is that true? The actual number of times d appears is x // d, which we did not compute. How do we know that x // d in fact equals i?
That's the purpose of the if d >= i: guarding that comment. After d = x // i we know that
x == d*i + r
for some integer r satisfying 0 <= r < i. That's essentially what floor division means. But since d >= i is also known (that's what the if test ensures), it must also be the case that 0 <= r < d. And that's how we know x // d is i.
This can break down when d >= i is not true, which is why a different method needs to be used then. For example, if x == 500 and i == 51, d (x // i) is 9, but it's certainly not the case that 9 is the largest divisor that appears 51 times. In fact, 9 appears 500 // 9 == 55 times. While for positive real numbers
d == x/i
if and only if
i == x/d
that's not always so for floor division. But, as above, the first does imply the second if we also know that d >= i.
Just for Fun
better5() rewrites better4() for about another 10% speed gain. The real pedagogical point is to show that it's easy to compute all the loop limits in advance. Part of the point of the odd code structure above is that it magically returns 0 for a 0 input without needing to test for that. better5() gives up on that:
def isqrt(n):
"Return floor(sqrt(n)) for int n > 0."
g = 1 << ((n.bit_length() + 1) >> 1)
d = n // g
while d < g:
g = (d + g) >> 1
d = n // g
return g
def better5(x):
assert x > 0
u = isqrt(x)
v = x // u
return (sum(map(sum3, (x // d for d in range(1, u+1)))) +
sum(x // i * i**3 for i in range(1, v)) -
u * sum3(v-1))
def sum_divisors(n):
sum = 0
i = 0
for i in range (1, n) :
if n % i == 0 and n != 0 :
sum = sum + i
# Return the sum of all divisors of n, not including n
return sum
print(sum_divisors(0))
# 0
print(sum_divisors(3)) # Should sum of 1
# 1
print(sum_divisors(36)) # Should sum of 1+2+3+4+6+9+12+18
# 55
print(sum_divisors(102)) # Should be sum of 2+3+6+17+34+51
# 114