How to calculate no. of palindroms in a large number interval? - python

I want to calculate how many numbers are palindrome in large interval data say 10^15
My simple code (python) snippet is:
def count_palindromes(start, end):
count = 0
for i in range(start, end + 1):
if str(i) == str(i)[::-1]:
count += 1
return count
start = 1000 #some initial number
end = 10000000000000 #some other large number
if __name__ == "__main__":
print count_palindromes(start, end)
Its a simple program which checks each number one by one. Its vary time consuming and takes a lot of computer resources.
Is there any other method/technique by which we can count Palindrome numbers? Any Algorithm to use for this?
I want to minimize time taken in producing the output.

When you want to count the numbers having some given property between two limits, it is often useful to solve the somewhat simpler problem
How many numbers with the given property are there between 0 and n?
Keeping one limit fixed can make the problem significantly simpler to tackle. When the simpler problem is solved, you can get the solution to the original problem with a simple subtraction:
countBetween(a,b) = countTo(b) - countTo(a)
or countTo(b ± 1) - countTo(a ± 1), depending on whether the limit is included in countTo and which limits shall be included in countBetween.
If negative limits can occur (not for palindromes, I presume), countTo(n) should be <= 0 for negative n (one can regard the function as an integral with respect to the counting measure).
So let us determine
palindromes_below(n) = #{ k : 0 <= k < n, k is a palindrome }
We get more uniform formulae for the first part if we pretend that 0 is not a palindrome, so for the first part, we do that.
Part 1: How many palindromes with a given number d of digits are there?
The first digit cannot be 0, otherwise it's unrestricted, hence there are 9 possible choices (b-1 for palindromes in an arbitrary base b).
The last digit is equal to the first by the fact that it shall be a palindrome.
The second digit - if d >= 3 - can be chosen arbitrarily and independently from the first. That also determines the penultimate digit.
If d >= 5, one can also freely choose the third digit, and so on.
A moment's thought shows that for d = 2*k + 1 or d = 2*k + 2, there are k digits that can be chosen without restriction, and one digit (the first) that is subject to the restriction that it be non-zero. So there are
9 * 10**k
d-digit palindromes then ((b-1) * b**k for base b).
That's a nice and simple formula. From that, using the formula for a geometric sum, we can easily obtain the number of palindromes smaller than 10n (that is, with at most n digits):
if n is even, the number is
n/2-1 n/2-1
2 * ∑ 9*10**k = 18 * ∑ 10**k = 18 * (10**(n/2) - 1) / (10 - 1) = 2 * (10**(n/2) - 1)
k=0 k=0
if n is odd, the number is
2 * (10**((n-1)/2) - 1) + 9 * 10**((n-1)/2) = 11 * (10**((n-1)/2) - 2
(for general base b, the numbers are 2 * (b**(n/2) - 1) resp. (b+1) * b**((n-1)/2) - 2).
That's not quite as uniform anymore, but still simple enough:
def palindromes_up_to_n_digits(n):
if n < 1:
return 0
if n % 2 == 0:
return 2*10**(n//2) - 2
else:
return 11*10**(n//2) - 2
(remember, we don't count 0 yet).
Now for the remaining part. Given n > 0 with k digits, the palindromes < n are either
palindromes with fewer than k digits, there are palindromes_up_to_n_digits(k-1) of them, or
palindromes with exactly k digits that are smaller than n.
So it remains to count the latter.
Part 2:
Letm = (k-1)//2 and
d[1] d[2] ... d[m] d[m+1] ... d[k]
the decimal representation of n (the whole thing works with the same principle for other bases, but I don't explicitly mention that in the following), so
k
n = ∑ d[j]*10**(k-j)
j=1
For each 1 <= c[1] < d[1], we can choose the m digits c[2], ..., c[m+1] freely to obtain a palindrome
p = c[1] c[2] ... c[m+1] {c[m+1]} c[m] ... c[2] c[1]
(the digit c[m+1] appears once for odd k and twice for even k). Now,
c[1]*(10**(k-1) + 1) <= p < (c[1] + 1)*10**(k-1) <= d[1]*10**(k-1) <= n,
so all these 10**m palindromes (for a given choice of c[1]!) are smaller than n.
Thus there are (d[1] - 1) * 10**m k-digit palindromes whose first digit is smaller than the first digit of n.
Now let us consider the k-digit palindromes with first digit d[1] that are smaller than n.
If k == 2, there is one if d[1] < d[2] and none otherwise. If k >= 3, for each 0 <= c[2] < d[2], we can freely choose the m-1 digits c[3] ... c[m+1] to obtain a palindrome
p = d[1] c[2] c[3] ... c[m] c[m+1] {c[m+1]} c[m] ... c[3] c[2] d[1]
We see p < n:
d[1]*(10**(k-1) + 1) + c[2]*(10**(k-2) + 10)
<= p < d[1]*(10**(k-1) + 1) + (c[2] + 1)*(10**(k-2) + 10)
<= d[1]*(10**(k-1) + 1) + d[2]*(10**(k-2) + 10) <= n
(assuming k > 3, for k == 3 replace 10**(k-2) + 10 with 10).
So that makes d[2]*10**(m-1) k-digit palindromes with first digit d[1] and second digit smaller than d[2].
Continuing, for 1 <= r <= m, there are
d[m+1]*10**(m-r)
k-digit palindromes whose first r digits are d[1] ... d[r] and whose r+1st digit is smaller than d[r+1].
Summing up, there are
(d[1]-1])*10**m + d[2]*10**(m-1) + ... + d[m]*10 + d[m+1]
k-digit palindromes that have one of the first m+1 digits smaller than the corresponding digit of n and all preceding digits equal to the corresponding digit of n. Obviously, these are all smaller than n.
There is one k-digit palindrome p whose first m+1 digits are d[1] .. d[m+1], we must count that too if p < n.
So, wrapping up, and now incorporating 0 too, we get
def palindromes_below(n):
if n < 1:
return 0
if n < 10:
return n # 0, 1, ..., n-1
# General case
dec = str(n)
digits = len(dec)
count = palindromes_up_to_n_digits(digits-1) + 1 # + 1 for 0
half_length = (digits-1) // 2
front_part = dec[0:half_length + 1]
count += int(front_part) - 10**half_length
i, j = half_length, half_length+1
if digits % 2 == 1:
i -= 1
while i >= 0 and dec[i] == dec[j]:
i -= 1
j += 1
if i >= 0 and dec[i] < dec[j]:
count += 1
return count
Since the limits are both to be included in the count for the given problem (unless the OP misunderstood), we then have
def count_palindromes(start, end):
return palindromes_below(end+1) - palindromes_below(start)
for a fast solution:
>>> bench(10**100,10**101-1)
900000000000000000000000000000000000000000000000000 palindromes between
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
and
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
in 0.000186920166016 seconds

Actually, it's a problem for Google Codejam (which I'm pretty sure you're not supposed to get outside help on) but alas, I'll throw in my 2 cents.
The idea I came up with (but failed to implement) for the large problem was to precompile (generated at runtime, not hardcoded into the source) a list of all palindromic numbers less than 10^15 (there's not very many, it takes like ~60 seconds) then find out how many of those numbers lie between the bounds of each input.
EDIT: This won't work on the 10^100 problem, like you said, that would be a mathematical solution (although there is a pattern if you look, so you'd just need an algorithm to generate all numbers with that pattern)

I presume this is for something like Project Euler... my rough idea would be to generate all numbers up to half the length of your limit (like, if you're going to 99999, go up to 99). Then reverse them, append them to the unreversed one, and potentially add a digit in the middle (for the numbers with odd lengths). You'll might have to do some filtering for duplicates, or weird ones (like if you had a zero at the beginning of the number or sommat) but that should be a lot faster than what you were doing.

Related

Number of occurrences of digit in numbers from 0 to n

Given a number n, count number of occurrences of digits 0, 2 and 4 including n.
Example1:
n = 10
output: 4
Example2:
n = 22
output: 11
My Code:
n = 22
def count_digit(n):
count = 0
for i in range(n+1):
if '2' in str(i):
count += 1
if '0' in str(i):
count += 1
if '4' in str(i):
count += 1
return count
count_digit(n)
Code Output: 10
Desired Output: 11
Constraints: 1 <= N <= 10^5
Note: The solution should not cause outOfMemoryException or Time Limit Exceeded for large numbers.
You can increment your count like this:
def count_digit(n):
count = 0
for i in range(n + 1):
if '2' in str(i):
count += str(i).count('2')
if '0' in str(i):
count += str(i).count('0')
if '4' in str(i):
count += str(i).count('4')
return count
In that way, edge cases like 22, 44, and so on are covered!
There are numbers in which the desired number is repeated, such as 20 or 22, so instead of adding 1 you must add 2
>>>
>>> string = ','.join(map(str,range(23)))
>>>
>>> string
'0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
>>>
>>> string.count('0') + string.count('2') + string.count('4')
11
>>>
n = 22
def count_digit(n):
count = 0
for i in map(str,range(n+1)):
count+=i.count('0')
count+=i.count('2')
count+=i.count('3')
return count
print(count_digit(n))
that solotion is fast:
It can be developed to be faster:
def count_digit(n):
i=0
count=0
s='024'
while i<n-1:
j = 0
for v in str(i):
if v in s:
j+=1
count+=3*j + (7*(j-1))
i+=10
for i in range(i,n+1,1):
for v in str(i):
if v in s:
count+=1
return count
TL;DR: If you do it right, you can compute the count about a thousand times faster for n close to 10**5, and since the better algorithm uses time proportional to the number of digits in n, it can easily handle even values of n too large for a 64-bit integer.
As is often the case with puzzles like this ("in the numbers from x to y, how many...?"), the key is to find a way to compute an aggregate count, ideally in O(1), for a large range. For combinatorics over the string representation of numbers, a convenient range is often something like the set of all numbers whose string representation is a given size, possibly with a specific prefix. In other words, ranges of the form [prefix*10⁴, prefix*10⁴+9999], where 0s in the lower limit is the same as the number of 9s in the upper limit and the exponent of 10 in the multiplier. (It's often actually more convenient to use half-open ranges, where the lower limit is inclusive and the upper limit is exclusive, so the above example would be [prefix*10⁴, (prefix+1)*10⁴).)
Also note that if the problem is to compute a count for [x, y), and you only know how to compute [0, y), then you just do two computations, because
count [x, y) == count [0, y) - count [0, x)
That identity is one of the simplifications which half-open intervals allow.
That would work nicely with this problem, because it's clear how many times a digit d occurs in the set of all k-digit suffixes for a given prefix. (In the 10k suffixes, every digit has the same frequency as every other digit; there are a total of k×10k digits in those 10k, and since all digits have the same count, that count must be k×10k−1.) Then you just have to add the digit count of the prefixes, but the prefix appears exactly 10k times, and each one contributes the same count.
So you could take a number like 72483, and decompose it into the following ranges, which roughly correspond to the sum of the digits in 72483, plus a few ranges containing fewer digits.
[0, 9]
[10, 99]
[100, 999]
[1000, 9999]
[10000, 19999]
[20000, 29999]
[30000, 39999]
[40000, 49999]
[50000, 59999]
[60000, 69999]
[70000, 70999]
[71000, 71999]
[72000, 72099]
[72100, 72199]
[72200, 72299]
[72300, 72399]
[72400, 72409]
[72410, 72419]
[72420, 72429]
[72430, 72439]
[72440, 72449]
[72450, 72459]
[72460, 72469]
[72470, 72479]
[72480, 72480]
[72481, 72481]
[72482, 72482]
[72483, 72483]
However, in the following code, I used a slightly different algorithm, which turned out to be a bit shorter. It considers the rectangle in which all the mumbers from 0 to n are written out, including leading zeros, and then computes counts for each column. A column of digits in a rectangle of sequential integers follows a simple recurring pattern; the frequency can easily be computed by starting with the completely repetitive part of the column. After the complete repetitions, the remaining digits are in order, with each one except the last one appearing the same number of times. It's probably easiest to understand that by drawing out a small example on a pad of paper, but the following code should also be reasonably clear (I hope).
The one problem with that is that it counts leading zeros which don't actually exist, so it needs to be corrected by subtracting the leading zero count. Fortunately, that count is extremely easy to compute. If you consider a range ending with a five-digit number (which itself cannot start with a zero, since it wouldn't really be a five-digit number if it started with zero), then you can see that the range includes:
10000 numbers start with a zero
1000 more numbers which have a second leading zero
100 more numbers which have a third leading zero
10 more numbers which have a fourth leading zero
No numbers have five leading zeros, because we write 0 as such, not as an empty string.
That adds up to 11110, and it's easy to see how that generalises. That value can be computed without a loop, as (10⁵ − 1) / 9 − 1. That correction is done at the end of the following function:
def countd(m, s=(0,2,4)):
if m < 0: return 0
m += 1
rv = 0
rest = 0
pos = 1
while True:
digit = m % 10
m //= 10
rv += m * pos * len(s)
for d in s:
if digit > d:
rv += pos
elif digit == d:
rv += rest
if m == 0:
break
rest += digit * pos
pos *= 10
if 0 in s:
rv -= (10 * pos - 1) // 9 - 1
return rv
That code could almost certainly be tightened up; I was just trying to get the algorithm down. But, as it is, it's execution time is measured in microseconds, not milliseconds, even for much larger values of n.
Here's an update of Kelly's benchmark; I removed the other solutions because they were taking too long for the last value of n:
Try it online!
Another brute force, seems faster:
def count_digit(n):
s = str(list(range(n+1)))
return sum(map(s.count, '024'))
Benchmark with n = 10**5:
result time solution
115474 244 ms original
138895 51 ms Kelly
138895 225 ms islam_abdelmoumen
138895 356 ms CodingDaveS
Code (Try it online!):
from timeit import default_timer as time
def original(n):
count = 0
for i in range(n+1):
if '2' in str(i):
count += 1
if '0' in str(i):
count += 1
if '4' in str(i):
count += 1
return count
def Kelly(n):
s = str(list(range(n+1)))
return sum(map(s.count, '024'))
def islam_abdelmoumen(n):
count = 0
for i in map(str,range(n+1)):
count+=i.count('0')
count+=i.count('2')
count+=i.count('3')
return count
def CodingDaveS(n):
count = 0
for i in range(n + 1):
if '2' in str(i):
count += str(i).count('2')
if '0' in str(i):
count += str(i).count('0')
if '4' in str(i):
count += str(i).count('4')
return count
funcs = original, Kelly, islam_abdelmoumen, CodingDaveS
print('result time solution')
print()
for _ in range(3):
for f in funcs:
t = time()
print(f(10**5), ' %3d ms ' % ((time()-t)*1e3), f.__name__)
print()
I ended up with a similar answer to rici's, except maybe from a slightly different phrasing for the numeric formulation. How many instances of each digit in each position ("counts for each column," as rici described) we can formulate in two parts as first p * floor(n / (10 * p)), where p is 10 raised to the power of position. For example, in position 0 (the rightmost), there is one 1 for each ten numbers. Counting the 0's, however, requires an additional check regarding the population of the current and next position.
To the first part we still need to add the counts attributed to the remainder of the division. For example, for n = 6, floor(6 / 10) = 0 but we do have one count of 2 and one of 4. We add p if the digit in that position in n is greater than the digit we're counting; or, if the digit is the same, we add the value on the right of the digit plus 1 (for example, for n = 45, we want to count the 6 instances where 4 appears in position 1: 40, 41, 42, 43, 44, 45).
JavaScript code, comparing with rici's instantly for all numbers from 1 to 600,000. (If I'm not mistaken, rici's code wrongly returns 0 for n = 0, when the answer should be 1 count.
function countd(m, s = [0,2,4]) {
if (m <= 0)
return 0
m += 1
rv = 0
rest = 0
pos = 1
while (true) {
digit = m % 10
m = Math.floor(m / 10)
rv += m * pos * s.length
for (d of s) {
if (digit > d)
rv += pos
else if (digit == d)
rv += rest
}
if (m == 0) {
break
}
rest += digit * pos
pos *= 10
}
if (s.includes(0)) {
rv -= Math.floor((10 * pos - 1) / 9) - 1
}
return rv
}
function f(n, ds = [0, 2, 4]) {
// Value on the right of position
let curr = 0;
let m = n;
// 10 to the power of position
let p = 1;
let result = 1;
while (m) {
const digit = m % 10;
m = Math.floor(m / 10);
for (const d of ds) {
if (d != 0 || n >= 11 * p) {
result += p * Math.floor((n - (d ? 0 : 10 * p)) / (10 * p));
}
if (digit > d && (d != 0 || m > 0)) {
result += p;
} else if (digit == d) {
result += curr + 1;
}
}
curr += p * digit;
p *= 10;
}
return result;
}
for (let n = 1; n <= 600000; n += 1) {
const _f = f(n);
const _countd = countd(n);
if (_f != _countd) {
console.log(`n: ${ n }`);
console.log(_f, _countd);
break;
}
}
console.log("Done.");
Using single branch conditional
def count_digit(n):
s = '024'
out = 0
for integer in map(str, range(n+1)): # integer as string
for digit in integer:
if digit in s:
out += 1
return out
or more compactly
def count_digit(n):
s = '024'
return sum(1 for i in map(str, range(n+1)) for d in i if d in s)

Probability that n is achieved by multiplying two random integers from two given ranges

So here is the challenge: I am given four numbers: a,b,c,d. Then the number n is given which describes how many numbers to check will be. Then these numbers are inputted and the goal is to find which probability that number will be gotten if multiply two random numbers one from the range a to b and one from c to d range. Finally, I need to output that probability in 'p/q' format. I figured out the solution and it works but the problem is when working with bigger numbers it uses too much time. I also have another solution where I first create a list with all possible combinations but in that case it uses too much memory.
from math import gcd
a,b,c,d = (map(int,input().split(" ")))
combs_quantity = (b-a+1)*(d-c+1)
def findProb(z):
repeats = 0
nec_mulps = [z//x for x in range(a,b+1) if z%x == 0]
for n in nec_mulps:
if n in range(c,d+1):
repeats+=1
probGCD = gcd(repeats,combs_quantity)
return str(repeats//probGCD) + "/" + str(combs_quantity//probGCD)
probability = []
n = int(input())
for i in range(n):
probability.append(findProb(int(input())))
for p in probability:
print(p)
Get all divisors of n
For every divisor Z that belongs to range a..b check whether complementary divisor n//Z lies in range c..d
#MBo said above that complexity is sqrt(z). You can to calculcate repeats as:
divisors = []
i = 1
while i * i <= z:
if z % i == 0:
divisors.append(i)
if i * i < z:
divisors.append(z // i)
i += 1
repeats = 0
for divisor in divisors:
if a <= divisor <= b and c <= z // divisor <= d:
repeats += 1

How to find even sum

I need to find the sum of all even numbers below the inserted number. For example if I insert 8 then the sum would be 2+4+6+8=20. If I insert 9 then it also needs to be 20. And it needs to be based on recursion.
This is what I have so far:
def even(a):
if a == 0:
else:
even(a - 1)
even(8)
I cannot figure out what to change under the "if" part for it to give the right outcome
If the function is called with an odd number, n, then you can immediately call again with the number below (an even).
Then if the function is called with an even number return that even number plus the result of summing all the even numbers below this number by calling again with n - 2.
Finally, your base case occurs when n = 0. In this case just return 0.
So we have
def even_sum(n):
if n % 2 == 1: # n is odd
return even_sum(n - 1)
if n == 0:
return 0
return n + even_sum(n - 2)
which works as expected
>>> even_sum(8)
20
>>> even_sum(9)
20
>>> even_sum(0)
0
To design a recursive algorithm, the first thing to wonder is "In what cases can my algorithm return an answer trivially?". In your case, the answer is "If it is called with 0, the algorithm answers 0". Hence, you can write:
def even(n):
if n == 0:
return 0
Now the next question is "Given a particular input, how can I reduce the size of this input, so that it will eventually reach the trivial condition?"
If you have an even number, you want to have this even number + the sum of even numbers below it, which is the result of even(n-2). If you have an odd number, you want to return the sum of even numbers below it. Hence the final version of your function is:
def even(n):
if n == 0 or n == 1:
return 0
if n % 2 == 0:
return n + even(n - 2)
return even(n - 1)
Both with o(n) time complexity
With For loop
num = int(input("Enter a number: ")) # given number to find sum
my_sum = 0
for n in range(num + 1):
if n % 2 == 0:
my_sum += n
print(my_sum)
With recursion
def my_sum(num):
if num == 0:
return 0
if num % 2 == 1:
return my_sum(num - 1)
return num + my_sum(num - 2)
always avoid O(n^2) and greater time complexity
For a recursive solution:
def evenSum(N): return 0 if N < 2 else N - N%2 + evenSum(N-2)
If you were always given an even number as input, you could simply recurse using N + f(N-2).
For example: 8 + ( 6 + (4 + ( 2 + 0 ) ) )
But the odd numbers will require that you strip the odd bit in the calculation (e.g. subtracting 1 at each recursion)
For example: 9-1 + ( 7-1 + ( 5-1 + ( 3-1 + 0 ) ) )
You can achieve this stripping of odd bits by subtracting the modulo 2 of the input value. This subtracts zero for even numbers and one for odd numbers.
adjusting your code
Your approach is recursing by 1, so it will go through both the even and odd numbers down to zero (at which point it must stop recursing and simply return zero).
Here's how you can adjust it:
Return a value of zero when you are given zero as input
Make sure to return the computed value that comes from the next level of recursion (you are missing return in front of your call to even(a-1)
Add the parameter value when it is even but don't add it when it is odd
...
def even(a):
if a == 0 : return 0 # base case, no further recusion
if a%2 == 1 : return even(a-1) # odd number: skip to even number
return a + even(a-1) # even number: add with recursion
# a+even(a-2) would be better
A trick to create a recursive function
An easy way to come up with the structure of a recursive function is to be very optimistic and imagine that you already have one that works. Then determine how you would use the result of that imaginary function to produce the next result. That will be the recursive part of the function.
Finally, find a case where you would know the answer without using the function. That will be your exit condition.
In this case (sum of even numbers), imagine you already have a function magic(x) that gives you the answer for x. How would you use it to find a solution for n given the result of magic(n-1) ?
If n is even, add it to magic(n-1). If n is odd, use magic(n-1) directly.
Now, to find a smaller n where we know the answer without using magic(). Well if n is less than 2 (or zero) we know that magic(n) will return zero so we can give that result without calling it.
So our recursion is "n+magic(n-1) if n is even, else magic(n-1)"
and our stop condition is "zero if n < 2"
Now substitute magic with the name of your function and the magic is done.
For an O(1) solution:
Given that the sum of numbers from 1 to N can be calculated with N*(N+1)//2, you can get half of the sum of even numbers if you use N//2 in the formula. Then multiply the result by 2 to obtain the sum of even numbers.
so (N//2)*(N//2+1) will give the answer directly in O(1) time:
N = 8
print((N//2)*(N//2+1))
# 20
# other examples:
for N in range(10):
print(N,N//2*(N//2+1))
# 0 0
# 1 0
# 2 2
# 3 2
# 4 6
# 5 6
# 6 12
# 7 12
# 8 20
# 9 20
Visually, you can see the progression like this:
1..n : 1 2 3 4 5 6 7 8
∑n : 1 3 6 10 15 21 28 36 n(n+1)/2
n/2 : 0 1 1 2 2 3 3 4
1..n/2 : 1 2 3 4
∑n/2 : 1 3 5 10 half of the result
2∑n/2 : 2 6 10 20 sum of even numbers
So we simply replace N with N//2 in the formula and multiply the result by 2:
N*(N+1)//2 --> replace N with N//2 --> N//2*(N//2+1)//2
N//2*(N//2+1)//2 --> multiply by 2 --> N//2*(N//2+1)
Another way to see it is using Gauss's visualisation of the sum of numbers but using even numbers:
ascending 2 4 6 8 ... N-6 N-4 N-2 N (where N is even)
descending N N-2 N-4 N-6 ... 8 6 4 2
--- --- --- --- --- --- --- ---
totals N+2 N+2 N+2 N+2 ... N+2 N+2 N+2 N+2 (N/2 times N+2)
Because we added the even numbers twice, once in ascending order and once in descending order, the sum of all the totals will be twice the sum of even numbers (we need to divide that sum by 2 to get what we are looking for).
sum of evens: N/2*(N+2)/2 --> N/2*(N/2+1)
The N/2(N/2+1) formulation allows us to supply the formula with an odd number and get the right result by using integer division which absorbs the 'odd bit': N//2(N//2+1)
Recursive O(1) solution
Instead of using the integer division to absorb the odd bit, you could use recursion with the polynomial form of N/2*(N+2)/2: N^2/4 + N/2
def sumEven(n):
if n%2 == 0 : return n**2/4 + n/2 # exit condition
return sumEven(n-1) # recursion
Technically this is recursive although in practice it will never go deeper than 1 level
Try out this.
>>> n = 5
>>> sum(range(0, n+1, 2))
with minimum complexity
# include <stdio.h>
void main()
{
int num, sum, i;
printf("Number: ");
scanf("%d", &num);
i = num;
if (num % 2 != 0)
num = num -1;
sum = (num * (num + 2)) / 4;
printf("The sum of even numbers upto %d is %d\n\n", i, sum);
}
It is a C program and could be used in any language with respective syntax.
And it needs to be based on recursion.
Though you want a recursion one, I still want to share this dp solution with detailed steps to solve this problem.
Dynamic Programming
dp[i] represents the even sum among [0, i] which I denote as nums.
Case1: When i is 0, there is one number 0 in nums. dp[0] is 0.
Case2: When i is 1, there are two numbers 0 and 1 in nums. dp[1] is still 0.
Case3: When i is 2, there are three numbers 0, 1 and 2 in nums. dp[2] is 2.
Case4: When i is greater than 2, there are two more cases
If i is odd, dp[i] = dp[i-1]. Since i is odd, it is the same with [0, i-1].
If i is even, dp[i] = dp[i-2] + i by adding the current even number to the even sum among [0, i-2] (i-1 is odd, so won't be added).
PS. dp[i] = dp[i-1] + i is also ok. The difference is how you initialize dp.
Since we want the even sum among [0, n], we return dp[n]. You can conclude this from the first three cases.
def even_sum(n):
dp = []
# Init
dp.append(0) # dp[0] = 0
dp.append(0) # dp[1] = 0
# DP
for i in range(2, n+1): # n+1 because range(i, j) results [i, j) and you take n into account
if i % 2 == 1: # n is odd
dp.append(dp[i-1]) # dp[i] = dp[i-1]
else: # n is even
dp.append(dp[i-2] + i) # dp[i] = dp[i-2] + i
return dp[-1]

How to avoid lists when analyzing order for palindromes?

Just want to apologize in advance for the general coding and logic gore you might encounter while reading this. I recently discovered Project Euler and thought it was fun. I've made it a point to not only find the answer, but make a generic function that could find the answer for any similar case given the appropriate input. For instance, problem number 4, involving palindromes, which can be seen here: https://projecteuler.net/problem=4
Essentially what I did was found a way to multiply every possible combination of numbers given a number of digits, n, then found products that were palindromes. However, anything above 3 digits just takes way too long to process. I believe this is because I used the list() function to take advantage of indexing to determine whether the product was a palindrome. Is there another way to do something of this nature? I feel like this is shoving a square through a circular hole.
Here's the function in question.
def palindrome(n):
number = 0
for i in range(0,n):
number = number + 9 * pow(10, i)
a = pow(10, n - 1) - 1
b = pow(10, n - 1)
while a * b < number * number:
a = a + 1
b = a
while b <= number:
c = a * b
b = b + 1
digits = list(str(int(c)))
lastdigits = digits[::-1]
numdigits = len(digits)
middle = int((numdigits - (numdigits % 2)) / 2) - 1
if numdigits > 1 and digits[:middle + 1] == lastdigits[:middle + 1] and digits[0] == digits[-1] == '9' and numdigits == 2 * n:
print(c)
"Find the largest palindrome made from the product of two 3-digit numbers."
3-digit numbers would be anything from 100 - 999. One thing about the largest product is guaranteed: The two operands must be as large as possible.
Thus, it would make sense to step through a loop starting from the largest number (999) to the smallest (100). We can append palindromes to a list and then later return the largest one.
When you calculate a product, convert it to a string using str(...). Now, checking for palindromes is easy thanks to python's string splicing. A string is a palindrome if string == string[::-1], where string[::-1] does nothing but return a reversed copy of the original.
Implementing these strategies, we have:
def getBiggestPalindrome():
max_palindrome = -1
for i in range(999, 99, -1):
for j in range(999, i - 1, -1):
prod = i * j
str_prod = str(prod)
if str_prod == str_prod[::-1] and prod > max_palindrome:
print(prod)
max_palindrome = prod
return max_palindrome
getBiggestPalindrome()
And, this returns
>>> getBiggestPalindrome()
906609
Note that you can use the range function to generate values from start, to end, with step. The iteration stops just before end, meaning the last value would be 100.

Efficient algorithm to find the count of numbers that are divisible by a number without a remainder in a range

Let's say I have two numbers: 6 and 11 and I am trying to find how many numbers between this range are divisible by 2 (3, in this case).
I have this simple code right now:
def get_count(a, b, m):
count = 0
for i in range(a, b + 1):
if i % m == 0:
count += 1
return count
Its order of growth is linear, O(N), I believe.
I was wondering if there is a faster algorithm with a constant O(1) performance, or a mathematical formula.
I don't expect a direct answer. The name of such an algorithm would be awesome.
Thank you.
((b - b%m) - a)//m+1 seems to work for me. I doubt it has a name. Another formula that seems to work is (b//m) - ((a-1)//m).
Sample python3 program:
def get_count(a, b, m):
return (((b - (b % m)) - a) // m) + 1
for i in range(5, 8):
for j in range(10, 13):
print(get_count(i, j, 2), end=" ")
print()
You are counting even numbers. Let's write o for odd, E for even.
If the sequence has an even count of numbers, it is either oEoE...oE or EoEo...Eo, i.e. one half of numbers is always even. If there is odd count of numbers, you can check the first number (or last one) separately and the rest is the known case discussed first.
def count_even(start, end):
# assert start <= end
len = end - start
len2, r = divmod(len, 2)
if r and start % 2 == 0:
len2 += 1
return len2
To find the count of all numbers between 0 and n that are divisible by two. you can use the bitwise operation called right shift;
c = a >> 1;
10 >> 1 is equivalent to floor(10/2)
You can subtract the two resultant numbers and get numbers between any range.
This will work in O(1). Hope this helps.

Categories

Resources