Determining the number of possible combinations - python

I'm trying to figure out how many possible ways there are to combine various elements form this string.
"{Hello|Hi|Hey} {world|earth}{!|.|?}"
Where one item (separated by a pipe/|) is selected at random from each group ({}) and combined into a single string.
So the above "template" could produce:
Hello world.
Hi earth?
Hey world.
Hi world?
I'm guessing this is a type of permutation, but I want to make sure I'm getting this right.
It would be really nice if this worked with "n" nested items as well.
"{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}"
I'd prefer a math/statistics based solution over brute-force looping to get the answer if possible.
Thanks!

Well, there are 3 x 2 x 3 = 18 combinations in your first example.
Your second example is 3 x 4 x 2 x 3 = 72 combinations.
I'm not entirely sure what you mean by {a|b}|{c|d} though, I'm assuming you mean pick one of either (a or b) or (c or d), which is 4 choices.
You might want to read up on combinations here or here.
Update: Yep, it's that simple. Your problem is exactly like counting the number of combinations of digits in a number. For example, if I want to find the number of combinations of an ATM PIN number (4 decimal digits), I have sets {0-9}, {0-9}, {0-9}, {0-9}. There are 10 possibilities for the first choice (= 10). For each of those numbers, there are 10 possibilities for the second choice (= 10 × 10). For each of those, there are 10 for the third (= 10 × 10 × 10) and 10 for the fourth (= 10 × 10 × 10 × 10 = 10,000). It should be intuitively clear that there are 10,000 possibilities for a 4 digit decimal number.
Your example uses sets of words instead of sets of digits, but the principle is the same. The number of combinations is the number of items in set 1 × number of items in set 2 × ... × number of items in set n, etc.
It gets more complicated when you start putting restrictions in, or are picking multiple items from the same set, etc.

The problem breaks down to two simple sub-problems:
count how many combinations are within braces and separated within vbars, for each braces pair
multiply those numbers
So for 1 I'd go with a plain regular expression + looping approach:
import re
def docount(thestring):
x = re.compile(r'{([^}]}')
counts = [mo.group(0).count('|')+1 for mo in x.finditer(thestring)]
result = 1
for c in counts: result *= c
return result
I've embedded 2 as well since that's the most trivial part anyway (if you're keen on using reduce for such purposes, that's OK too in lieu of the last three lines, I guess;-).

Related

Number N denoting the length of the inputted array

While solving some progrmaming problems, I've noticed that the dialogue says:
Input:
Integer N denoting size of array
Next line contains N space separated integers denoting elements in
array
How am I supposed to use the variable N so that it is functioning as supposed to and not just a useless-floating-around input-variable...
I mean, it could just be one input denoting the elements of the array, no need for the length of its elements...
PS: I know that I can just add it there just to pass the problem, I am just asking about if that N variable could be useful using Python (Without the way of a for loop, to ask N number of times for input cause it won't pass the problem).
In Python it usually is, since usually you fetch the entire line at once and process it.
Some programming languages like C++ and Java however tend to benefit from this approach since some parser tools (like Java's Scanner) work by parsing one integer at a time.
You can simply parse your input like:
input() # ignore the 'N'
arr = [int(x) for x in input().split()]
x=list(map(int,input().split())
print(x)
Try this
you will get an array of integers
If I understood you correctly, you want space-separated numbers with the length defined as the input. You can achieve that by:
N = input("Integer N denoting size of array: ")
print(" ".join(str(i + 1) for i in range(int(N))))
e.g.:
Integer N denoting size of array: 12
1 2 3 4 5 6 7 8 9 10 11 12

Alphanumeric sorting in Python and negative numbers

I have a fairly simple list (a number followed by a sentence), here in the right order:
-347 a negative number
-100 another negative number
-25 and again, a negative number
17 some text
25 foo bar
100 two same texts
100 two same texts (almost)
350 a positive number
I need to sort that list each time a new item is added.
I searched S.O. and found that answer :
Sorting in python - how to sort a list containing alphanumeric values?
The code I used is freakish’s, which goes :
import re
def convert(str):
return int("".join(re.findall("\d*", str)))
list1.sort(key=convert)
In order to better explain my problem, I shuffled the list and ran the code.
The result was :
17 some text
-25 and again, a negative number
25 foo bar
100 two same texts (almost)
100 two same texts
-100 another negative number
-347 a negative number
350 a positive number
What went wrong ? What is the precision in the code that would sort naturally the negative numbers?
Sort can accept a tuple, so first sort by the number, then by the text after
list_text = """-347 a negative number
-100 another negative number
-25 and again, a negative number
17 some text
25 foo bar
100 two same texts
100 two same texts (almost)
350 a positive number"""
list1 = list_text.split("\n")
list1.sort(key=lambda x: (int(x.split()[0]), x.split(" ",1)))
print("\n".join(list1))
The easiest approach, IMHO, would be to split the string to individual words, and then sort by the first word converted to an int:
list1.sort(key = lambda x : int(x.split(" ")[0]))
EDIT:
As Keatinge, the above solution won't properly handle two strings that start with the same number. Using the entire string as a secondary search term should solve this issue:
list1.sort(key = lambda x : (int(x.split(" ")[0]), x)

Programs that Find Numbers Divisible by 5 or 3

i want to make a program to find how many number is divisible by 3 or 5 in a number for example 10 has 3 9 6 divisible by 3 and has 5 and 10 divisible by 5 so total is 5 and so on so i write my code
import math
n=float(raw_input())
div3=(n-2)/3
div5=(n-4)/5
f1=math.ceil(div3)
f2=math.ceil(div5)
sumss=f1+f2
print int(sumss)
but in some number it get wrong answer and the range of input number will be
from 1 to 10^18 so i need to use math in it because the time limit for the problem test is 2 second any one have any efficiently equation to make that the loop cant make it it take very long time
This is probably a project Euler question. The issue is that some numbers can be shared by 3 and 5. For instance 22:
divisors of 3: 3 6, 9, 12, 15, 18, 21.
divisors of 5: 5 10, 15, 20
For both 15 occurs, so you did a double count.
The advantage is that 3 and 5 are relatively prime, so the only numbers that are shared are the ones dividable by 15. So you simply need to undo the double counting:
n=int(raw_input())
div3=n//3
div5=n//5
div15=n//15
sumss=div3+div5-div15
print sumss
In case you allow double counting (15 should be counted twice), you can simply use:
n=int(raw_input())
div3=n//3
div5=n//5
sumss=div3+div5
print sumss
Note that the programs omitted the floating point arithmetic: this will result in both faster and more precise programs since floating point numbers work with a limited mantisse and thus can fail to represent a large number correctly (resulting by small errors). Furthermore in general integer arithmetic is faster.
Project Euler #1
Now the problem statement of Project Euler is a bit different: it asks to sum up these numbers. In order to do that, you have to construct an expression to sum up the first k multiples of l:
k
---
\
/ l*i
---
i=1
Using Wolfram Alpha, one gets this expression. So you can calculate these as:
def suml (k,l) :
return k*(k+1)*l/2
n=int(raw_input())
div3=n//3
div5=n//5
div15=n//15
sumss=suml(div3,3)+suml(div5,5)-suml(div15,15)
print sumss
This program gives 119 for n=22 which - you can verify above - is correct if you count 15 only once.
I am not sure whether I got the question right, but here is some idea:
n=float(raw_input())
div3=int(n/3)
div5=int(n/5)
div15=int(n/15)
sumss=div3+div5-div15
print sumss
EDIT: Ah, found the project Euler.
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.
That is a different task then the question posted here. It says bellow the number and to find the sum.
I am not sure whether it would be the right thing to post the solution here, so I am rather not doing that.
EDIT2: from Project Euler:
We hope that you enjoyed solving this problem. Please do not deprive
others of going through the same process by publishing your solution
outside Project Euler. If you want to share your insights then please
go to thread 1 in the discussion forum.

Computing persistence number of an integer

I am trying to make a code that does the following:
Multiplying the digits of an integer and continuing the process gives
the surprising result that the sequence of products always arrives at
a single-digit number.
For example:
715 -> 35 -> 15 -> 5
88 -> 64 -> 24 -> 8
27 -> 14 -> 4
The number of products necessary to reach the single-digit
number is called the persistence number of that integer. Thus 715
and 88 have a persistence number of 3, while 27 has persistence 2.
Make a program to find the only two-digit number with persistence
greater than 3?
I was able to come up with a rough idea and the code is below but it doesn't seem to work:
num2=0
num3=0
num4=0
num=input("what is your number?")
while num in range(10,100):
print 'step1'
num1=num%10*num/10
if num1-10>10:
print 'step2'
num2=num1%10*num1/10
elif num2-num1>10:
print 'step3'
num3=num2%10*num2/10
elif num3-num2>10:
print 'step4'
num4=num3%10*num3/10
elif num4-num3>10:
print 'step5'
print num4
else:
break
The program is Python and I simply can't figure this out. If someone could possibly help me I would appreciate it greatly!
You should use a while or for loop to multiply the digits instead of hardcoding what to do with the first, second and so on digits.
In pseudocode...
productSoFar = 1
digitsLeftToMultipy = #the number
while there are digits left to multiply:
get the next digit and
update produtsSoFar and digitsLeftToMultiply
Also, use
10 <= n < 100
instead of
n in range(10, 100)
So you only do a couple of comparisons instead of a sequential lookup that takes time proportional to the length of the range.
Functions are friends.
Consider a function, getEnds(x), which when passed an integer, x will extract the first digit and the last digit (as integers) and return the result as a tuple in the form (first_digit, last_digit). If x is a single-digit number the tuple will contain one element and be in the form (x), otherwise it will be two. (A simple way to do this is to turn the number into a string, extract the first/last digit as a string, and then convert said strings back into numbers... however, there are many ways: just make sure to honor the function contract, as stated above and -- hopefully -- in the function documentation.)
Then, where n is the current number we are finding the persistence for:
ends = getEnds(n)
while ends contains two elements
n = first element of ends times second element of ends
ends = getEnds(n)
# while terminates when ends contained only one element
# now it's only a matter of "counting" the persistence
For added points, make sure this is in a -- [an] appropriately named/documented -- function as well and consider the use of a recursive function instead of a while-loop.
Happy coding.
If you're trying to get the digits of a number, convert it into a string first and reference them with array notation.

Combinatorics Counting Puzzle: Roll 20, 8-sided dice, what is the probability of getting at least 5 dice of the same value

Assume a game in which one rolls 20, 8-sided die, for a total number of 8^20 possible outcomes. To calculate the probability of a particular event occurring, we divide the number of ways that event can occur by 8^20.
One can calculate the number of ways to get exactly 5 dice of the value 3. (20 choose 5) gives us the number of orders of 3. 7^15 gives us the number of ways we can not get the value 3 for 15 rolls.
number of ways to get exactly 5, 3's = (20 choose 5)*7^15.
The answer can also be viewed as how many ways can I rearrange the string 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 (20 choose 5) times the total number of values we the zero's (assuming 7 legal values) 7^15 (is this correct).
Question 1: How can I calculate the number of ways to get exactly 5 dice of the same value(That is, for all die values).
Note: if I just naively use my first answer above and multiply bt 8, I get an enormous amount of double counting?
I understand that I could solve for each of the cases (5 1's), (5, 2's), (5, 3's), ... (5's, 8) sum them (more simply 8*(5 1's) ). Then subtract the sum of number of overlaps (5 1's) and (5 2's), (5 1's) and (5 3's)... (5 1's) and (5, 2's) and ... and (5, 8's) but this seems exceedingly messy. I would a generalization of this in a way that scales up to large numbers of samples and large numbers of classes.
How can I calculate the number of ways to get at least 5 dice of the same value?
So 111110000000000000000 or 11110100000000000002 or 11111100000001110000 or 11011211222222223333, but not 00001111222233334444 or 000511512252363347744.
I'm looking for answers which either explain the math or point to a library which supports this (esp python modules). Extra points for detail and examples.
I suggest that you spend a little bit of time writing up a Monte Carlo simulation and let it run while you work out the math by hand. Hopefully the Monte Carlo simulation will converge before you're finished with the math and you'll be able to check your solution.
A slightly faster option might involve creating a SO clone for math questions.
Double counting can be solved by use of the Inclusion/Exclusion Principle
I suspect it comes out to:
Choose(8,1)*P(one set of 5 Xs)
- Choose(8,2)*P(a set of 5 Xs and a set of 5 Ys)
+ Choose(8,3)*P(5 Xs, 5 Ys, 5 Zs)
- Choose(8,4)*P(5 Xs, 5 Ys, 5 Zs, 5 As)
P(set of 5 Xs) = 20 Choose 5 * 7^15 / 8^20
P(5 Xs, 5 Ys) = 20 Choose 5,5 * 6^10 / 8^20
And so on. This doesn't solve the problem directly of 'more then 5 of the same', as if you simply summed the results of this applied to 5,6,7..20; you would over count the cases where you have, say, 10 1's and 5 8's.
You could probably apply inclusion exclusion again to come up with that second answer; so, P(of at least 5)=P(one set of 20)+ ... + (P(one set of 15) - 7*P(set of 5 from 5 dice)) + ((P(one set of 14) - 7*P(one set of 5 from 6) - 7*P(one set of 6 from 6)). Coming up with the source code for that is proving itself more difficult.
The exact probability distribution Fs,i of a sum of i s-sided dice can be calculated as the repeated convolution of the single-die probability distribution with itself.
where for all and 0 otherwise.
http://en.wikipedia.org/wiki/Dice
This problem is really hard if you have to generalize it (get the exact formula).
But anyways, let me explain the algorithm.
If you want to know
the number of ways to get exactly 5
dice of the same value
you have to rephrase your previous problem, as
calculate the number of ways to get
exactly 5 dice of the value 3 AND no
other value can be repeated exactly 5
times
For simplicity's sake, let's call function F(20,8,5) (5 dice, all values) the first answer, and F(20,8,5,3) (5 dice, value 3) the second.
We have that F(20,8,5) = F(20,8,5,3) * 8 + (events when more than one value is repeated 5 times)
So if we can get F(20,8,5,3) it should be pretty simple isn't it?
Well...not so much...
First, let us define some variables:
X1,X2,X3...,Xi , where Xi=number of times we get the dice i
Then:
F(20,8,5)/20^8 = P(X1=5 or X2=5 or ... or X8=5, with R=20(rolls) and N=8(dice number))
, P(statement) being the standard way to write a probability.
we continue:
F(20,8,5,3)/20^8 = P(X3=5 and X1<>5 and ... and X8<>5, R=20, N=8)
F(20,8,5,3)/20^8 = 1 - P(X1=5 or X2=5 or X4=5 or X5=5 or X6=5 or X7=5 or X8=5, R=15, N=7)
F(20,8,5,3)/20^8 = 1 - F(15,7,5)/7^15
recursively:
F(15,8,5) = F(15,7,5,1) * 7
P(X1=5 or X2=5 or X4=5 or X5=5 or X6=5 or X7=5 or X8=5, R=15, N=7) = P(X1=5 and X2<>5 and X4<>5 and .. and X8<>5. R=15, N=7) * 7
F(15,7,5,1)/7^15 = 1 - F(10,6,5)/6^10 F(10,6,5) = F(10,6,5,2) * 6
F(10,6,5,2)/6^10 = 1 - F(5,5,5)/5^5
F(5,5,5) = F(5,5,5,4) * 5
Well then... F(5,5,5,4) is the number of ways to get 5 dices of value 4 in 5 rolls, such as no other dice repeats 5 times. There is only 1 way, out of a total 5^5. The probability is then 1/5^5.
F(5,5,5) is the number of ways to get 5 dices of any value (out of 5 values) in 5 rolls. It's obviously 5. The probability is then 5/5^5 = 1/5^4.
F(10,6,5,2) is the number of ways to get 5 dices of value 2 in 10 rolls, such as no other dice repeats 5 times.
F(10,6,5,2) = (1-F(5,5,5)/5^5) * 6^10 = (1-1/5^4) * 6^10
Well... I think it may be incorrect at some part, but anyway, you get the idea. I hope I could make the algorithm understandable.
edit:
I did some checks, and I realized you have to add some cases when you get more than one value repeated exactly 5 times. Don't have time to solve that part thou...
Here is what I am thinking...
If you just had 5 dice, you would only have eight ways to get what you want.
For each of those eight ways, all possible combinations of the other 15 dice work.
So - I think the answer is: (8 * 815) / 820
(The answer for at least 5 the same.)
I believe you can use the formula of x occurrences in n events as:
P = probability^n * (n!/((n - x)!x!))
So the final result is going to be the sum of results from 0 to n.
I don't really see any easy way to combine it into one step that would be less messy. With this way you have the formula spelled out in the code as well. You may have to write your own factorial method though.
float calculateProbability(int tosses, int atLeastNumber) {
float atLeastProbability = 0;
float eventProbability = Math.pow( 1.0/8.0, tosses);
int nFactorial = factorial(tosses);
for ( i = 1; i <= atLeastNumber; i++) {
atLeastProbability += eventProbability * (nFactorial / (factorial(tosses - i) * factorial(i) );
}
}
Recursive solution:
Prob_same_value(n) = Prob_same_value(n-1) * (1 - Prob_noone_rolling_that_value(N-(n-1)))

Categories

Resources