Python find max number of combinations in binary - python

Hi I'm trying to figure out a function where given a length n of a list [x1, x2... xn], how many digits would be needed for a base 2 number system to assign a unique code to each value in the list.
For example, one digit can hold two unique values:
x1 0
x2 1
two digits can hold four:
x1 00
x2 01
x3 10
x4 11
etc. I'm trying to write a python function calcBitDigits(myListLength) that takes this list length and returns the number of digits needed. calcBitDigits(2) = 1, calcBitDigits(4) = 2, calcBitDigits(3) = 2, etc.

>>> for i in range(10):
... print i, i.bit_length()
0 0
1 1
2 2
3 2
4 3
5 3
6 3
7 3
8 4
9 4
I'm not clear on exactly what it is you want, but it appears you want to subtract 1 from what bit_length() returns - or maybe not ;-)
On third thought ;-), maybe you really want this:
def calcBitDigits(n):
return (n-1).bit_length()
At least that gives the result you said you wanted in each of the examples you gave.
Note: for an integer n > 0, n.bit_length() is the number of bits needed to represent n in binary. (n-1).bit_length() is really a faster way of computing int(math.ceil(math.log(n, 2))).
Clarification: I understand the original question now ;-) Here's how to think about the answer: if you have n items, then you can assign them unique codes using the n integers in 0 through n-1 inclusive. How many bits does that take? The number of bits needed to express n-1 (the largest of the codes) in binary. I hope that makes the answer obvious instead of mysterious ;-)
As comments pointed out, the argument gets strained for n=1. It's a quirk then that (0).bit_length() == 0. So watch out for that one!

Use the following -
import math
int(math.ceil(math.log(x,2)))
where x is the list length.
Edit:
For x = 1, we need to have a separate case that would return 1. Thanks #thefourtheye for pointing this out.

I am not comfortable with the other answers, since most of them fail at the corner case (when n == 1). So, I wrote this based on Tim's answer.
def calcBitDigits(n):
if n <= 0: return 0
elif n <= 2: return 1
return (n-1).bit_length()
for i in range(10):
print i, calcBitDigits(i)
Output
0 0
1 1
2 1
3 2
4 2
5 3
6 3
7 3
8 3
9 4

x = int(log(n,2))+1
x will be the number of bits required to store the integer value n.

If for some reason you don't want to use .bit_length, here's another way to find it.
from itertools import count
def calcBitDigits(n):
return next(i for i in count() if 1<<i >= n)

Related

How do i optimize this code to run for larger values? [duplicate]

This question already has answers here:
Elegant Python code for Integer Partitioning [closed]
(11 answers)
Closed 1 year ago.
I'm writing a python function that takes an integer value between 3 and 200 as input, calculates the number of sums using unique nonzero numbers that will equal the number and prints the output.
For example; with 3 as input 1 will be printed because only 1 + 2 will give 3, with 6 as input 3 will be printed because 1+2+3, 1+5 and 2+4 equal 6.
My code works well only for numbers less than 30 after which it starts getting slow. How do I optimize my code to run efficiently for all input between 3 and 200.
from itertools import combinations
def solution(n):
count = 0
max_terms = 0
num = 0
for i in range(1,n):
if num + i <= n:
max_terms += 1
num = num + i
for terms in range(2,max_terms + 1):
for sample in list(combinations(list(range(1,n)),terms)):
if sum(sample) == n:
count += 1
print(count)
Generating all combinations is indeed not very efficient as most will not add up to n.
Instead, you could use a recursive function, which can be called after taking away one partition (i.e. one term of the sum), and will solve the problem for the remaining amount, given an extra indication that future partitions should be greater than the one just taken.
To further improve the efficiency, you can use memoization (dynamic programming) to avoid solving the same sub problem multiple times.
Here is the code for that:
def solution(n, least=1, memo={}):
if n < least:
return 0
key = (n, least)
if key in memo: # Use memoization
return memo[key]
# Counting the case where n is not partitioned
# (But do not count it when it is the original number itself)
count = int(least > 1)
# Counting the cases where n is partitioned
for i in range(least, (n + 1) // 2):
count += solution(n - i, i + 1)
memo[key] = count
return count
Tested the code with these arguments. The comments list the sums that are counted:
print(solution(1)) # none
print(solution(2)) # none
print(solution(3)) # 1+2
print(solution(4)) # 1+3
print(solution(5)) # 1+4, 2+3
print(solution(6)) # 1+2+3, 1+5, 2+4
print(solution(7)) # 1+2+4, 1+6, 2+5, 3+4
print(solution(8)) # 1+2+5, 1+3+4, 1+7, 2+6, 3+5
print(solution(9)) # 1+2+6, 1+3+5, 2+3+4, 1+8, 2+7, 3+6, 4+5
print(solution(10)) # 1+2+3+4, 1+2+7, 1+3+6, 1+4+5, 2+3+5, 1+9, 2+8, 3+7, 4+6
your question isn't clear enough. So, I'm making some assumptionns...
So, what you want is to enter a number. say 4 and then, figure out the total combinations where two different digits add up to that number. If that is what you want, then the answer is quite simple.
for 4, lets take that as 'n'. 'n' has the combinations 1+3,2+2.
for n as 6, the combos are - 1+5,2+4,3+3.
You might have caught a pattern. (4 and 6 have half their combinations) also, for odd numbers, they have combinations that are half their previous even number. i.e. - 5 has (4/2)=2 combos. i.e. 1+4,2+3 so...
the formula to get the number for comnbinations are -
(n)/2 - this is if you want to include same number combos like 2+2 for 4 but, exclude combos with 0. i.e. 0+4 for 4
(n+1)/2 - this works if you want to exclude either the combos with 0 i.e. 0+4 for 4 or the ones with same numbers i.e. 2+2 for 4.
(n-1)/2 - here, same number combos are excluded. i.e. 2+2 wont be counted as a combo for n as 4. also, 0 combos i.e. 0+4 for 4 are excluded.
n is the main number. in these examples, it is '4'. This will work only if n is an integer and these values after calculations are stored as an integer.
3 number combos are totally different. I'm sure there's a formula for that too.

initialization in while loop

I'm new to python and having problem understanding the code snippet below.
I don't understand why sum is initialized to 0, not 1. Can anyone explain this initialization?
n = 4
sum = 0 # initialize sum
i = 1 # initialize counter
while i <= n:
sum = sum + i
i = i+1 # update counter
print("The sum is", sum)
This is actually more of a basics in computer programming than Python question. I'll try to explain in brief here.
Looks like your goal is to find the sum of integers 1 to n.
If you initialize the sum with 1, then the result you get will be always 1 more than the actual sum of integers 1 to n. You can verify that by doing runs with small values of n, say up to 5 and comparing the output you get with the actual sum. I'll put a table here for convenience:
n | sum(1, n)
-------------
1 | 1
2 | 3
3 | 6
4 | 10
5 | 15
Now compare this to the output when sum is initialized with 1. For curiosity's sake, you can play with initializing with other values too.
Sum is initialized to zero, but because the less than or equal to of n and i you always run at least one loop, take i = 1, then the sum is still one because the loop checks if 1 is less than or equal to 1 (i <= n). since it is then it adds i to the sum (ie. 1) making sum 1. it then updates i to 2 and goes to the top of the while loop. Since 2 <= 1 or i <= n is false here it breaks out and prints one as the sum

Project Euler's Multiples of 3 and 5 - Problem - Python [duplicate]

This question already has answers here:
Why is my Project Euler problem #1 code returning the wrong result?
(3 answers)
Closed 1 year ago.
I just tried to solve Problem 1 in Project Euler but I don't understand why this code is not working and the output answer is wrong.QUESTION - If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.Find the sum of all the multiples of 3 or 5 below 1000.
correct answer = 233168My output =266333
a = 0
for x in range(0,1000,3):
a = a + x
for x in range(0,1000,5):
a = a + x
print(a)
ProjectEuler #1
def f(x):
n1, n2, n3 = x//3, x//5, x//15
return 3*(n1)*(n1+1)//2+5*(n2)*(n2+1)//2-15*(n3)*(n3+1)//2
for i in range(int(input())):
print(f(int(input())-1))
Here x//3 gives int(x/3) similarly for x//5 and x//15
As LCM(3,5)=15
Σi = n(n+1)/2
answer= sum of multiples of 3 + sum of multiples of 5 - sum of multiples of 15.
corresponds to a solution of ProjectEulerProblem #1
Note: My intention of sharing codes on StackOverflow is to let people know that a given problem could be solved in many ways.
As it's always a difficult for one to pass all cases due to timeError.
Do not use as an answer but learn.
You are overcounting the multiples of 15. One way to fix this would be to have just one loop which checks if the number is a multiple of 3 or 5.
solution = 0
for i in range(1000):
if i % 3 == 0 or i % 5 == 0:
solution += i
print(solution)
The comment by Devesh Kumar Singh solves the question:
Because you count the multiples of both 3 and 5 twice, e.g. 15 . Add a loop for subtracting such values e.g. for x in range(0,1000,15): a = a - x

Algorithm: Factorize a integer X to get as many distinct positive integers(Y1...Yk) as possible so that (Y1+1)(Y2+1)...(Yk+1) = X

I recently met a algorithm question in open.kattis.com.
The question's link is https://open.kattis.com/problems/listgame2.
Basically, it is a question ask the players to factorize a integer X (10^3 <= X <= 10^15) to get as many distinct positive integers (Y1,...,Yk) as possible such that (Y1+1)(Y2+1)⋯(Yk+1) = X.
I already came up with a solution using Python3, which does pass several test cases but failed one of them:MyStatus
My code is:
def minFactor(n, start):
maxFactor = round(n**0.5)
for i in range(start, maxFactor+1):
if n % i == 0:
return i
return n
def distinctFactors(n):
curMaxFactor = 1
factors = []
while n > 1:
curMaxFactor = minFactor(n, curMaxFactor+1)
n //= curMaxFactor
factors.append(curMaxFactor)
# This is for the situation where the given number is the square of a prime number
# For example, when the input is 4, the returned factors would be [2,2] instead of [4]
# The if statement below are used to fix this flaw
# And since the question only requires the length of the result, deleting the last factor when repeat do works in my opinion
if factors[-1] in factors[:-1]:
del factors[-1]
return factors
num = int(input())
print(len(distinctFactors(num)))
Specifically, my idea inside the above code is quite simple. For example, when the given input is 36, I run the minFactor function to find that the minimum factor of 36 is 2 (1 is ignored in this case). Then, I get 18 by doing 36/2 and invoke minFactor(18,3) since 2 is no more distinct so I start to find the minimum factor of 18 by 3. And it is 3 clearly, so I get 6 by doing 18/3 in function distinctFactors and invoke minFactor(6,4), since 4 is smaller than sqrt(6) or 6**0.5 so 6 itself will be returned and I finally get the list factors as [2,3,6], which is correct.
I have scrutinised my code and algorithm for hours but I still cannot figure out why I failed the test case, could anyone help me with my dilemma??? Waiting for reply.
Consider the number 2**6.11**5.
Your algorithm will find 5 factors:
2
2**2
2**3
11
11**2
(11**2 this will be discarded as it is a repeat)
A 6 length answer is:
2
2**2
11
11**2
2*11
2**2*11

Sum of all numbers

I need to write a function that calculates the sum of all numbers n.
Row 1: 1
Row 2: 2 3
Row 3: 4 5 6
Row 4: 7 8 9 10
Row 5: 11 12 13 14 15
Row 6: 16 17 18 19 20 21
It helps to imagine the above rows as a 'number triangle.' The function should take a number, n, which denotes how many numbers as well as which row to use. Row 5's sum is 65. How would I get my function to do this computation for any n-value?
For clarity's sake, this is not homework. It was on a recent midterm and needless to say, I was stumped.
The leftmost number in column 5 is 11 = (4+3+2+1)+1 which is sum(range(5))+1. This is generally true for any n.
So:
def triangle_sum(n):
start = sum(range(n))+1
return sum(range(start,start+n))
As noted by a bunch of people, you can express sum(range(n)) analytically as n*(n-1)//2 so this could be done even slightly more elegantly by:
def triangle_sum(n):
start = n*(n-1)//2+1
return sum(range(start,start+n))
A solution that uses an equation, but its a bit of work to arrive at that equation.
def sumRow(n):
return (n**3+n)/2
The numbers 1, 3, 6, 10, etc. are called triangle numbers and have a definite progression. Simply calculate the two bounding triangle numbers, use range() to get the numbers in the appropriate row from both triangle numbers, and sum() them.
Here is a generic solution:
start=1
n=5
for i in range(n):
start += len (range(i))
answer=sum(range(start,start+n))
As a function:
def trio(n):
start=1
for i in range(n):
start += len (range(i))
answer=sum(range(start,start+n))
return answer
def sum_row(n):
final = n*(n+1)/2
start = final - n
return final*(final+1)/2 - start*(start+1)/2
or maybe
def sum_row(n):
final = n*(n+1)/2
return sum((final - i) for i in range(n))
How does it work:
The first thing that the function does is to calculate the last number in each row. For n = 5, it returns 15. Why does it work? Because each row you increment the number on the right by the number of the row; at first you have 1; then 1+2 = 3; then 3+3=6; then 6+4=10, ecc. This impy that you are simply computing 1 + 2 + 3 + .. + n, which is equal to n(n+1)/2 for a famous formula.
then you can sum the numbers from final to final - n + 1 (a simple for loop will work, or maybe fancy stuff like list comprehension)
Or sum all the numbers from 1 to final and then subtract the sum of the numbers from 1 to final - n, like I did in the formula shown; you can do better with some mathematical operations
def compute(n):
first = n * (n - 1) / 2 + 1
last = first + n - 1
return sum(xrange(first, last + 1))

Categories

Resources