count number of ones in a given integer - python

How do you count the number of ones in a given integer's binary representation.
Say you are given a number 20, which is 10100 in binary, so number of ones is 2.

What you're looking for is called the Hamming weight, and there are a lot of algorithms to do it. Here's another straightforward one:
def ones(n):
w = 0
while (n):
w += 1
n &= n - 1
return w

Use the awesome collections module.
>>> from collections import Counter
>>> binary = bin(20)[2:]
>>> Counter(binary)
Counter({'0': 3, '1': 2})
Or you can use the built-in function count():
>>> binary = bin(20)[2:]
>>> binary.count('1')
2
Or even:
>>> sum(1 for i in bin(20)[2:] if i == '1')
2
But that last solution is slower than using count()

>>> num = 20
>>> bin(num)[2:].count('1')
2

The usual way to make this blinding fast is to use lookup tables:
table = [bin(i)[2:].count('1') for i in range(256)]
def pop_count(n):
cnt = 0
while n > 0:
cnt += table[n & 255]
n >>= 8
return cnt
In Python, any solution using bin and list.count will be faster, but this is nice if you want to write it in assembler.

The int type has a new method int.bit_count() since python 3.10a, returning the number of ones in the binary expansion of a given integer, also known as the population count as follows:
n = 20
bin(n)
'0b10100'
n.bit_count() returns 2 as it has 2 ones in the binary representation.

The str.count method and bin function make short work of this little challenge:
>>> def ones(x):
"Count the number of ones in an integer's binary representation"
return bin(x).count('1')
>>> ones(20)
2

You can do this using bit shifting >> and bitwise and & to inspect the least significant bit, like this:
def count_ones(x):
result = 0
while x > 0:
result += x & 1
x = x >> 1
return result
This works by shifting the bits right until the value becomes zero, counting the number of times the least significant bit is 1 along the way.

I am a new coder and I found this one logic simple. Might be easier for newbies to understand.
def onesInDecimal(n):
count = 0
while(n!=0):
if (n%2!=0):
count = count+1
n = n-1
n = n/2
else:
n = n/2
return count

For a special case when you need to check quickly whether the binary form of the integer x has only a single 1 (and thus is a power of 2), you can use this check:
if x == -(x | (-x)):
...
The expression -(x | (-x)) is the number that you get if you replace all 1s except the last one (the least significant bit) in the binary representation of x with 0.
Example:
12 = 1100 in binary
-12 = ...110100 in binary (with an infinite number of leading 1s)
12 | (-12) = ...111100 in binary (with an infinite number of leading 1s)
-(12 | (-12)) = 100 in binary

If the input number is 'number'
number =20
len(bin(number)[2:].replace('0',''))
Another solution is
from collections import Counter
Counter(list(bin(number))[2:])['1']

Related

Does an algorithm exist that converts a (base 10) number to into another number for any base in constant time?

I am solving a problem where I am given three integers (a,b,c), all three can be very large and (a>b>c)
I want to identify for which base between b and c, produces the smallest sum of digits, when we convert 'a' to that base.
For example a = 216, b=2, c=7 -> the output= 6, because: 216 base 2 = 11011000, and the sum of digits = 4, if we do the same for all bases between 2 and 7, we find that 216 base 6 produces the smallest sum of digits, because 216 base 6 = 1000, which has sum 1.
My question is, is there any function out there that can convert a number to any base in constant time faster than the below algorithm? Or any suggestions on how to optimise my algorithm?
from collections import defaultdict
n = int(input())
for _ in range(n):
(N,X) = map(int,input().split())
array = list(map(int,input().split()))
my_dict = defaultdict(int)
#original count of elements in array
for i in range(len(array)):
my_dict[array[i]] +=1
#ensure array contains distinct elements
array = set(array)
count = max(my_dict.values()) #count= max of single value
temp = count
res = None
XOR_count = float("inf")
if X==0:
print(count,0)
break
for j in array:
if j^X in my_dict:
curr = my_dict[j^X] + my_dict[j]
if curr>=count:
count = curr
XOR_count = min(my_dict[j],XOR_count)
if count ==temp:
XOR_count = 0
print(f"{count} {XOR_count}")
Here are some sample input and outputs:
Sample Input
3
3 2
1 2 3
5 100
1 2 3 4 5
4 1
2 2 6 6
Sample Output
2 1
1 0
2 0
Which for the problem I am solving runs into time limit exceeded error.
I found this link to be quite useful (https://www.purplemath.com/modules/logrules5.htm) in terms of converting log bases, which I can kind of see how it relates, but I couldn't use it to get a solution for my above problem.
You could separate the problem in smaller concerns by writing a function that returns the sum of digits in a given base and another one that returns a number expressed in a given base (base 2 to 36 in my example below):
def digitSum(N,b=10):
return N if N<b else N%b+digitSum(N//b,b)
digits = "0123456789abcdefghijklmnopqrstuvwxyz"
def asBase(N,b):
return "" if N==0 else asBase(N//b,b)+digits[N%b]
def lowestBase(N,a,b):
return asBase(N, min(range(a,b+1),key=lambda c:digitSum(N,c)) )
output:
print(lowestBase(216,2,7))
1000 # base 6
print(lowestBase(216,2,5))
11011000 # base 2
Note that both digitSum and asBase could be written as iterative instead of recursive if you're manipulating numbers that are greater than base^1000 and don't want to deal with recursion depth limits
Here's a procedural version of digitSum (to avoid recursion limits):
def digitSum(N,b=10):
result = 0
while N:
result += N%b
N //=b
return result
and returning only the base (not the encoded number):
def lowestBase(N,a,b):
return min(range(a,b+1),key=lambda c:digitSum(N,c))
# in which case you don't need the asBase() function at all.
With those changes results for a range of bases from 2 to 1000 are returned in less than 60 milliseconds:
lowestBase(10**250+1,2,1000) --> 10 in 57 ms
lowestBase(10**1000-1,2,1000) --> 3 in 47 ms
I don't know how large is "very large" but it is still sub-second for millions of bases (yet for a relatively smaller number):
lowestBase(10**10-1,2,1000000) --> 99999 in 0.47 second
lowestBase(10**25-7,2,1000000) --> 2 in 0.85 second
[EDIT] optimization
By providing a maximum sum to the digitSum() function, you can make it stop counting as soon as it goes beyond that maximum. This will allow the lowestBase() function to obtain potential improvements more efficiently based on its current best (minimal sum so far). Going through the bases backwards also gives a better chance of hitting small digit sums faster (thus leveraging the maxSum parameter of digitSum()):
def digitSum(N,b=10,maxSum=None):
result = 0
while N:
result += N%b
if maxSum and result>=maxSum:break
N //= b
return result
def lowestBase(N,a,b):
minBase = a
minSum = digitSum(N,a)
for base in range(b,a,-1):
if N%base >= minSum: continue # last digit already too large
baseSum = digitSum(N,base,minSum)
if baseSum < minSum:
minBase,minSum = base,baseSum
if minSum == 1: break
return minBase
This should yield a significant performance improvement in most cases.

How to convert negative bit-represented numbers to their actual negative int value in python3?

Hello I have solved this leetcode question https://leetcode.com/problems/single-number-ii. The objective is to solve the problem in O(n) time and 0(1) space. The code I wrote is the following:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
counter = [0 for i in range(32)]
result = 0
for i in range(32):
for num in nums:
if ((num >> i) & 1):
counter[i] += 1
result = result | ((counter[i] % 3) << i)
return self.convert(result)
#return result
def convert(self,x):
if x >= 2**31:
x = (~x & 0xffffffff) + 1
x = -x
return x
Now the interesting part is in the convert function, since python uses objects to store int as opposed to a 32 bit word or something, it does not know that the result is negative when the MSB of my counter is set to 1. I handle that by converting it to its 2's complement and returning the negative value.
Now someone else posted their solution with:
def convert(self, x):
if x >= 2**31:
x -= 2**32
return x
And I can't figure out why that works. I need help understanding why this subtraction works.
The value of the highest bit of an unsigned n-bit number is 2n-1.
The value of the highest bit of a signed two's complement n-bit number is -2n-1.
The difference between those two values is 2n.
So if a unsigned n-bit number has the highest bit set, to convert to a two's complement signed number subtract 2n.
In a 32-bit number, if bit 31 is set, the number will be >= 231, so the formula would be:
if n >= 2**31:
n -= 2**32
I hope that makes it clear.
Python integers are infinitely large. They will not turn negative as you add more bits so two's complement may not work as expected. You could manage negatives differently.
def singleNumber(nums):
result = 0
sign = [1,-1][sum(int(n<0) for n in nums)%3]
for i in range(32):
counter = 0
for num in nums:
counter += (abs(num) >> i) & 1
result = result | ((counter % 3) << i)
return result * sign
This binary approach can be optimized and simplified like this:
def singleNumber(nums):
result = 0
for i in range(32):
counter = sum(1 for n in nums if (n>>i)&1)
if counter > 0: result |= (counter % 3) << i
return result - 2*(result&(1<<31))
If you like one liners, you can implement it using reduce() from functools:
result = reduce(lambda r,i:r|sum(1&(n>>i) for n in nums)%3<<i,range(32),sum(n<0 for n in nums)%3*(-1<<32))
Note that this approach will always do 32 passes through the data and will be limited to numbers in the range -2^31...2^31. Increasing this range will systematically augment the number of passes through the list of numbers (even if the list only contains small values). Also, since you're not using counter[i] outside of the i loop, you don't need a list to store the counters.
You could leverage base 3 instead of base 2 using a very similar approach (which also responds in O(n) time and O(1) space):
def singleNumber(nums):
result = sign = 0
for num in nums:
if num<0 : sign += 1
base3 = 1
num = abs(num)
while num > 0 :
num,rest = divmod(num,3)
rest,base3 = rest*base3, 3*base3
if rest == 0 : continue
digit = result % base3
result = result - digit + (digit+rest)%base3
return result * (1-sign%3*2)
This one has the advantage that it will go through the list only once (thus supporting iterators as input). It does not limit the range of values and will perform the nested while loop as few times as possible (in accordance with the magnitude of each value)
The way it works is by adding digits independently in a base 3 representation and cycling the result (digit by digit) without applying a carry.
For example: [ 16, 16, 32, 16 ]
Base10 Base 3 Base 3 digits result (cumulative)
------ ------ ------------- ------
16 121 0 | 1 | 2 | 1 121
16 121 0 | 1 | 2 | 1 212
32 2012 2 | 0 | 1 | 2 2221
16 121 0 | 1 | 2 | 1 2012
-------------
sum of digits % 3 2 | 0 | 1 | 2 ==> 32
The while num > 0 loop processes the digits. It will run at most log(V,3) times where V is the largest absolute value in the numbers list. As such it is similar to the for i in range(32) loop in the base 2 solution except that it always uses the smallest possible range. For any given pattern of values, the number of iterations of that while loop is going to be less or equal to a constant thus preserving the O(n) complexity of the main loop.
I made a few performance tests and, in practice, the base3 version is only faster than the base2 approach when values are small. The base3 approach always performs fewer iterations but, when values are large, it loses out in total execution time because of the overhead of modulo vs bitwise operations.
In order for the base2 solution to always be faster than the base 3 approach, it needs to optimize its iterations through the bits by reversing the loop nesting (bits inside numbers instead of numbers inside bits):
def singleNumber(nums):
bits = [0]*len(bin(max(nums,key=abs)))
sign = 0
for num in nums:
if num<0 : sign += 1
num = abs(num)
bit = 0
while num > 0:
if num&1 : bits[bit] += 1
bit += 1
num >>= 1
result = sum(1<<bit for bit,count in enumerate(bits) if count%3)
return result * [1,-1][sign%3]
Now it will outperform the base 3 approach every time. As a side benefit, it is no longer limited by a value range and will support iterators as input. Note that the size of the bits array can be treated as a constant so this is also a O(1) space solution
But, to be fair, if we apply the same optimization to the base 3 approach (i.e. using a list of base 3 'bits'), its performance comes back in front for all value sizes:
def singleNumber(nums):
tribits = [0]*len(bin(max(nums,key=abs))) # enough base 2 -> enough 3
sign = 0
for num in nums:
if num<0 : sign += 1
num = abs(num)
base3 = 0
while num > 0:
digit = num%3
if digit: tribits[base3] += digit
base3 += 1
num //= 3
result = sum(count%3 * 3**base3 for base3,count in enumerate(tribits) if count%3)
return result * [1,-1][sign%3]
.
Counter from collections would give the expected result in O(n) time with a single line of code:
from collections import Counter
numbers = [1,0,1,0,1,0,99]
singleN = next(n for n,count in Counter(numbers).items() if count == 1)
Sets would also work in O(n):
distinct = set()
multiple = [n for n in numbers if n in distinct or distinct.add(n)]
singleN = min(distinct.difference(multiple))
These last two solutions do use a variable amount of extra memory that is proportional to the size of the list (i.e. not O(1) space). On the other hand, they run 30 times faster and they will support any data type in the list. They also support iterators
32-bit signed integers wrap around every 2**32, so a positive number with the the sign bit set (ie >= 2**31) has the same binary representation as the negative number 2**32 less.
That is the very definition of two's complement code of a number A on n bits.
if number A is positive use the binary code of A
if A is negative, use the binary code of 2^n+A (or 2^n-|A|). This number is the one you have to add to |A| to get 2^n (i.e. the complement of |A| to 2^n, hence the name of the two's complement method).
So, if you have a negative number B coded in two's complement, what is actually in its code is 2^N+B. To get its value, you have to substract 2^N from B.
There are many other definitions of two's complement (~A+1, ~(A-1), etc), but this one is the most useful as it explains why adding signed two's complement numbers is absolutely identical to adding positive numbers. The number is in the code (with 2^32 added if negative) and the addition result will be correct, provided you ignore the 2^32 that may be generated as a carry out (and there is no overflow). This arithmetic property is the main reason why two's complement is used in computers.

Code for factoring doesn't work with large numbers?

I have a large 512 bit number n and I need to rewrite n-1 as m*2k
Here is the code I wrote:
# write (n-1) = m*2^k (where m is odd)
k = 0 # number of times we were able to divide by 2
total = (n-1)
while total % 2 == 0:
total /= 2
k += 1
m = int(total)
assert (n-1) == (2**k) * m # this does not hold true for large values of n for some reason
The problem is that it doesn't work for large (515 bit) values of n such as:
8711599454063889217821738854601954834373650047096243407624954758041578156381215983765719390767527065267731131102484447503200895621045535585981917487924709
For the above value of n, my code found k = 460 and m =2926172291557515
When I evaluate 2926172291557515 * 2**460 in python I get:
8711599454063889889401923055669626316647070894345982715097720460936366477064539266279767451213791729696559357170292404522606916263895951485640687369584640
Which does not equal n-1. Does anyone know why this could be happening? I assume it's related to having such large numbers (this code works fine for lower numbers that I test it with.
The problem arises because you are using /= which is float division. Replace it with //=, or integer division, and your code will work.
#Primusa is correct. In Python3.x / (or /=) returns a float value, so loses a lot of precision.
>>> n = 8711599454063889217821738854601954834373650047096243407624954758041578156381215983765719390767527065267731131102484447503200895621045535585981917487924709
>>> total = (n-1)
>>> total / 2
4.355799727031945e+153
>>> total // 2
4355799727031944608910869427300977417186825023548121703812477379020789078190607991882859695383763532633865565551242223751600447810522767792990958743962354

Unicode recursion for a number

I want to get any number. e.g: 14892. And return it as 25903
(according to each character's unicode value)
This is what I have so far:
def convert(n):
if len(n)>0:
x = (chr(ord(str((int(n[0])+1)))))
return x
def convert(n):
return int(''.join([str(int(elem)+1)[-1] for elem in str(n)]))
You could use a list comprehension.
To perform this transformation, you need to get each digit and add one to it, with 10 wrapping around to 0. The simple way to do that wrapping is to use the modulus operator. We can also use integer division and modulus to extract the digits, and we can do both operations using the built-in divmod function. We store the modified digits in a list, since the simple way to combine the digits back into a single number needs the digits in reverse order.
def convert(n):
a = []
while n:
n, r = divmod(n, 10)
a.append((r + 1) % 10)
n = 0
for u in reversed(a):
n = 10 * n + u
return n
# Test
print(convert(14892))
output
25903
That algorithm is fairly close to the usual way to do this transformation in traditional languages. However, in Python, it's actually faster to do this sort of thing using strings, since the str and int constructors can do most of their work at C speed. The resulting code is a little more cryptic, but much more compact.
def convert(n):
return int(''.join([str((int(c) + 1) % 10) for c in str(n)]))
You could convert the number to a string, use the translate function to swap out the numbers, and convert back to integer again:
>>> t=str.maketrans('1234567890','2345678901')
>>> x = 14892
>>> y = int(str(x).translate(t))
>>> y
25903

Unlucky number 13

I came across this problem Unlucky number 13! recently but could not think of efficient solution this.
Problem statement :
N is taken as input.
N can be very large 0<= N <= 1000000009
Find total number of such strings that are made of exactly N characters which don't include "13". The strings may contain any integer from 0-9, repeated any number of times.
# Example:
# N = 2 :
# output : 99 (0-99 without 13 number)
# N =1 :
# output : 10 (0-9 without 13 number)
My solution:
N = int(raw_input())
if N < 2:
print 10
else:
without_13 = 10
for i in range(10, int('9' * N)+1):
string = str(i)
if string.count("13") >= 1:
continue
without_13 += 1
print without_13
Output
The output file should contain answer to each query in a new line modulo 1000000009.
Any other efficient way to solve this ? My solution gives time limit exceeded on coding site.
I think this can be solved via recursion:
ans(n) = { ans([n/2])^2 - ans([n/2]-1)^2 }, if n is even
ans(n) = { ans([n/2]+1)*ans([n/2]) - ans([n/2])*ans([n/2]-1) }, if n is odd
Base Cases:
ans(0) = 1
ans(1) = 10
It's implementation is running quite fast even for larger inputs like 10^9 ( which is expected as its complexity is O(log[n]) instead of O(n) like the other answers ):
cache = {}
mod = 1000000009
def ans(n):
if cache.has_key(n):
return cache[n]
if n == 0:
cache[n] = 1
return cache[n]
if n == 1:
cache[n] = 10
return cache[n]
temp1 = ans(n/2)
temp2 = ans(n/2-1)
if (n & 1) == 0:
cache[n] = (temp1*temp1 - temp2*temp2) % mod
else:
temp3 = ans(n/2 + 1)
cache[n] = (temp1 * (temp3 - temp2)) % mod
return cache[n]
print ans(1000000000)
Online Demo
Explanation:
Let a string s have even number of digits 'n'.
Let ans(n) be the answer for the input n, i.e. the number of strings without the substring 13 in them.
Therefore, the answer for string s having length n can be written as the multiplication of the answer for the first half of the string (ans([n/2])) and the answer for the second half of the string (ans([n/2])), minus the number of cases where the string 13 appears in the middle of the number n, i.e. when the last digit of the first half is 1 and the first digit of the second half is 3.
This can expressed mathematically as:
ans(n) = ans([n/2])^2 - ans([n/2]-1)*2
Similarly for the cases where the input number n is odd, we can derive the following equation:
ans(n) = ans([n/2]+1)*ans([n/2]) - ans([n/2])*ans([n/2]-1)
I get the feeling that this question is designed with the expectation that you would initially instinctively do it the way you have. However, I believe there's a slightly different approach that would be faster.
You can produce all the numbers that contain the number 13 yourself, without having to loop through all the numbers in between. For example:
2 digits:
13
3 digits position 1:
113
213
313 etc.
3 digits position 2: 131
132
133 etc.
Therefore, you don't have to check all the number from 0 to n*9. You simply count all the numbers with 13 in them until the length is larger than N.
This may not be the fastest solution (in fact I'd be surprised if this couldn't be solved efficiently by using some mathematics trickery) but I believe it will be more efficient than the approach you have currently taken.
This a P&C problem. I'm going to assume 0 is valid string and so is 00, 000 and so on, each being treated distinct from the other.
The total number of strings not containing 13, of length N, is unsurprisingly given by:
(Total Number of strings of length N) - (Total number of strings of length N that have 13 in them)
Now, the Total number of strings of length N is easy, you have 10 digits and N slots to put them in: 10^N.
The number of strings of length N with 13 in them is a little trickier.
You'd think you can do something like this:
=> (N-1)C1 * 10^(N-2)
=> (N-1) * 10^(N-2)
But you'd be wrong, or more accurately, you'd be over counting certain strings. For example, you'd be over counting the set of string that have two or more 13s in them.
What you really need to do is apply the inclusion-exclusion principle to count the number of strings with 13 in them, so that they're all included once.
If you look at this problem as a set counting problem, you have quite a few sets:
S(0,N): Set of all strings of Length N.
S(1,N): Set of all strings of Length N, with at least one '13' in it.
S(2,N): Set of all strings of Length N, with at least two '13's in it.
...
S(N/2,N): Set of all strings of Length N, with at least floor(N/2) '13's in it.
You want the set of all strings with 13 in them, but counted at most once. You can use the inclusion-exclusion principle for computing that set.
Let f(n) be the number of sequences of length n that have no "13" in them, and g(n) be the number of sequences of length n that have "13" in them.
Then f(n) = 10^n - g(n) (in mathematical notation), because it's the number of possible sequences (10^n) minus the ones that contain "13".
Base cases:
f(0) = 1
g(0) = 0
f(1) = 10
g(1) = 0
When looking for the sequences with "13", a sequence can have a "13" at the beginning. That will account for 10^(n-2) possible sequences with "13" in them. It could also have a "13" in the second position, again accounting for 10^(n-2) possible sequences. But if it has a "13" in the third position, and we'd assume there would also be 10^(n-2) possible sequences, we could those twice that already had a "13" in the first position. So we have to substract them. Instead, we count 10^(n-4) times f(2) (because those are exactly the combinations in the first two positions that don't have "13" in them).
E.g. for g(5):
g(5) = 10^(n-2) + 10^(n-2) + f(2)*10^(n-4) + f(3)*10^(n-5)
We can rewrite that to look the same everywhere:
g(5) = f(0)*10^(n-2) + f(1)*10^(n-3) + f(2)*10^(n-4) + f(3)*10^(n-5)
Or simply the sum of f(i)*10^(n-(i+2)) with i ranging from 0 to n-2.
In Python:
from functools import lru_cache
#lru_cache(maxsize=1024)
def f(n):
return 10**n - g(n)
#lru_cache(maxsize=1024)
def g(n):
return sum(f(i)*10**(n-(i+2)) for i in range(n-1)) # range is exclusive
The lru_cache is optional, but often a good idea when working with recursion.
>>> [f(n) for n in range(10)]
[1, 10, 99, 980, 9701, 96030, 950599, 9409960, 93149001, 922080050]
The results are instant and it works for very large numbers.
In fact this question is more about math than about python.
For N figures there is 10^N possible unique strings. To get the answer to the problem we need to subtract the number of string containing "13".
If string starts from "13" we have 10^(N-2) possible unique strings. If we have 13 at the second possition (e.i. a string like x13...), we again have 10^(N-2) possibilities. But we can't continue this logic further as this will lead us to double calculation of string which have 13 at different possitions. For example for N=4 there will be a string "1313" which we will calculate twice. To avoid this we should calculate only those strings which we haven't calculated before. So for "13" on possition p (counting from 0) we should find the number of unique string which don't have "13" on the left side from p, that is for each p
number_of_strings_for_13_at_p = total_number_of_strings_without_13(N=p-1) * 10^(N-p-2)
So we recursevily define the total_number_of_strings_without_13 function.
Here is the idea in the code:
def number_of_strings_without_13(N):
sum_numbers_with_13 = 0
for p in range(N-1):
if p < 2:
sum_numbers_with_13 += 10**(N-2)
else:
sum_numbers_with_13 += number_of_strings_without_13(p) * 10**(N-p-2)
return 10**N - sum_numbers_with_13
I should say that 10**N means 10 in the power of N. All the other is described above. The functions also has a surprisingly pleasent ability to give correct answers for N=1 and N=2.
To test this works correct I've rewritten your code into function and refactored a little bit:
def number_of_strings_without_13_bruteforce(N):
without_13 = 0
for i in range(10**N):
if str(i).count("13"):
continue
without_13 += 1
return without_13
for N in range(1, 7):
print(number_of_strings_without_13(N),
number_of_strings_without_13_bruteforce(N))
They gave the same answers. With bigger N bruteforce is very slow. But for very large N recursive function also gets mush slower. There is a well known solution for that: as we use the value of number_of_strings_without_13 with parameters smaller than N multiple times, we should remember the answers and not recalculate them each time. It's quite simple to do like this:
def number_of_strings_without_13(N, answers=dict()):
if N in answers:
return answers[N]
sum_numbers_with_13 = 0
for p in range(N-1):
if p < 2:
sum_numbers_with_13 += 10**(N-2)
else:
sum_numbers_with_13 += number_of_strings_without_13(p) * 10**(N-p-2)
result = 10**N - sum_numbers_with_13
answers[N] = result
return result
Thanks to L3viathan's comment now it is clear. The logic is beautiful.
Let's assume a(n) is a number of strings of n digits without "13" in it. If we know all the good strings for n-1, we can add one more digit to the left of each string and calculate a(n). As we can combine previous digits with any of 10 new, we will get 10*a(n-1) different strings. But we must subtract the number of strings, which now starts with "13" which we wrongly summed like OK at the previous step. There is a(n-2) of such wrongly added strings. So a(n) = 10*a(n-1) - a(n-2). That is it. Such simple.
What is even more interesting is that this sequence can be calculated without iterations with a formula https://oeis.org/A004189 But practically that doesn't helps much, as the formula requires floating point calculations which will lead to rounding and would not work for big n (will give answer with some mistake).
Nevertheless the original sequence is quite easy to calculate and it doesn't need to store all the previous values, just the last two. So here is the code
def number_of_strings(n):
result = 0
result1 = 99
result2 = 10
if n == 1:
return result2
if n == 2:
return result1
for i in range(3, n+1):
result = 10*result1 - result2
result2 = result1
result1 = result
return result
This one is several orders faster than my previous suggestion. And memory consumption is now just O(n)
P.S. If you run this with Python2, you'd better change range to xrange
This python3 solution meets time and memory requirement of HackerEarth
from functools import lru_cache
mod = 1000000009
#lru_cache(1024)
def ans(n):
if n == 0:
return 1
if n == 1:
return 10
temp1 = ans(n//2)
temp2 = ans(n//2-1)
if (n & 1) == 0:
return (temp1*temp1 - temp2*temp2) % mod
else:
temp3 = ans(n//2 + 1)
return (temp1 * (temp3 - temp2)) % mod
for t in range(int(input())):
n = int(input())
print(ans(n))
I came across this problem on
https://www.hackerearth.com/problem/algorithm/the-unlucky-13-d7aea1ff/
I haven't been able to get the judge to accept my solution(s) in Python but (2) in ANSI C worked just fine.
Straightforward recursive counting of a(n) = 10*a(n-1) - a(n-2) is pretty slow when getting to large numbers but there are several options (one which is not mentioned here yet):
1.) using generating functions:
https://www.wolframalpha.com/input/?i=g%28n%2B1%29%3D10g%28n%29+-g%28n-1%29%2C+g%280%29%3D1%2C+g%281%29%3D10
the powers should be counted using squaring and modulo needs to be inserted cleverly into that and the numbers must be rounded but Python solution was slow for the judge anyway (it took 7s on my laptop and judge needs this to be counted under 1.5s)
2.) using matrices:
the idea is that we can get vector [a(n), a(n-1)] by multiplying vector [a(n-1), a(n-2)] by specific matrix constructed from equation a(n) = 10*a(n-1) - a(n-2)
| a(n) | = | 10 -1 | * | a(n-1) |
| a(n-1) | | 1 0 | | a(n-2) |
and by induction:
| a(n) | = | 10 -1 |^(n-1) * | a(1) |
| a(n-1) | | 1 0 | | a(0) |
the matrix multiplication in 2D should be done via squaring using modulo. It should be hardcoded rather counted via for cycles as it is much faster.
Again this was slow for Python (8s on my laptop) but fast for ANSI C (0.3s)
3.) the solution proposed by Anmol Singh Jaggi above which is the fastest in Python (3s) but the memory consumption for cache is big enough to break memory limits of the judge. Removing cache or limiting it makes the computation very slow.
You are given a string S of length N. The string S consists of digits from 1-9, Consider the string indexing to be 1-based.
You need to divide the string into blocks such that the i block contains the elements from the index((i 1) • X +1) to min(N, (i + X)) (both inclusive). A number is valid if it is formed by choosing exactly one digit from each block and placing the digits in the order of their block
number

Categories

Resources