Count the moves of hanoi tower - python

I am trying to count the moves of hanoi tower
In [4]: %paste
count = 0
def hanoi(n, a, b, c):
global count
if n == 1:
count += 1
else:
hanoi(n - 1, a, c, b)
hanoi(1, a, b, c)
hanoi(n - 1, b, a, c)
hanoi(10, "A", "B", "C")
## -- End pasted text --
In [5]: print(count)
1023
The above solution employed the global keyword,
How could get it done if not introducing global?

With a bit of refactoring to make the function recursive with a common count variable:
def hanoi(n, a, b, c):
count = 0
if n == 1:
count += 1
else:
count += hanoi(n - 1, a, c, b)
count += hanoi(1, a, b, c)
count += hanoi(n - 1, b, a, c)
return count
Output
>>> hanoi(10, "A", "B", "C")
1023

Or even without any count variable:
def hanoi(n, a, b, c):
if n != 1:
return hanoi(n - 1, a, c, b) + hanoi(1, a, b, c) + hanoi(n - 1, b, a, c)
return 1
print (hanoi(10, "A", "B", "C"))
Output
1023

There is no need to use complex codes for that. After all, that is math based, so just use this simple one line solution, that works every time in every code.
Place it in the end of hanoi code using tab ofc... but before
hanoi(10, "A", "B", "C")
and remove all that "count" staff that was never even needed.
print(2**n-1)
Lets say, your hanoi code ends like this, with this math code:
def hanoi(n,f,h,t,):
if n==0:
pass
else:
hanoi(n-1,f,t,h)
move(f,t)
hanoi(n-1,h,f,t)
print(2**n-1)
hanoi(4,"A","B","C")
And you do not have to make an other code to count that. Just chance the number at the and of code. Less is better and faster...
If you make all codes long and spread, it will slow down the results. PC:s are made to do math, so why should we not use that!?
The other thing is that, hanoi code itself is easier to make than these count codes. Lets compare with this randint code...
Hanoi code needs just one print/format on it like this:
print("Move object from {} to {}!" .format(f,t))
You can also get rid of int and str in code. Any option, you can cut out of code, makes its faster and cleaner. When there is millions of codes, this comes reasonable to do. Unless you want to hide something in/out of master code.
Reason is, there is only one starting/end point. Empty points (when ever they are empty) are only "help" points. I'm not going to go too deep to that.
But in the end...
Combinatorics in math or even in Python, gives your starting/end points and numbers of events in how many(n), where(A,B,C...) and some times when and even timers/triggers(there is many options)
Learning Hanoi Tower is useful and powerful, to understand, so when your make your code, your can use these given options and print them, with simple math code instead, of doing complex codes with errors. If you like, you can ad there as many tiny hanoi codes as you like and still, you can get right answer(just separate them with r or n option to row or new line).
I hope this was better answer now, after explanation of combinatorics.

Related

find index of first occurrence of str from given str

Google or Amazone ask the following question in an interview, would my solution be accepted?
problem: find the index of the first occurrence of the given word from the given string
note: Above problem is from a website and following code passed all the test cases. however, I am not sure if this is the most optimum solutions and so would be accepted by big giants.
def strStr(A, B):
if len(A) == 0 or len(B) == 0:
return -1
for i in range(len(A)):
c = A[i:i+len(B)]
if c == B:
return i
else:
return -1
There are a few algorithms that you can learn on this topic like
rabin karp algorithm , z algorithm ,kmpalgorithm
which all run in run time complexity of O(n+m) where n is the string length and m is the pattern length. Your algorithm runs in O(n*m) runtime complexity . I would suggest starting to learn from rabin karp algorithm, I personally found it the easiest to grasp.
There are also some advanced topics like searching many patterns in one string like the aho-corasick algorithm which is good to read. I think this is what grep uses when searching for multiple patterns.
Hope it helps :)
Python actually has a built in function for this, which is why this question doesn't seem like a great fit for interviews in python. Something like this would suffice:
def strStr(A, B):
return A.find(B)
Otherwise, as commenters have mentioned, inputs/outputs and tests are important. You could add some checks that make it slightly more performant (i.e. check that B is smaller than A), but I think in general, you won't do better than O(n).
If you want to match the entire word to the words in the string, your code would not work.
E.g If my arguments are print(strStr('world hello world', 'wor')), your code would return 0, but it should return -1.
I checked your function, works well in python3.6
print(strStr('abcdef', 'bcd')) # with your function. *index start from 0
print("adbcdef".find('bcd')) # python default function. *index start from 1
first occurrence index, use index() or find()
text = 'hello i am homer simpson'
index = text.index('homer')
print(index)
index = text.find('homer')
print(index)
output:
11
11
It is always better to got for the builtin python funtions.
But sometimes in the interviews they will ask for you to implemente it yourself. The best thing to do is to start with the simplest version, then think about corner cases and improvements.
Here you have a test with your version, a slightly improved one that avoid to reallocating new strings in each index and the python built-ing:
A = "aaa foo baz fooz bar aaa"
B = "bar"
def strInStr1(A, B):
if len(A) == 0 or len(B) == 0:
return -1
for i in range(len(A)):
c = A[i:i+len(B)]
if c == B:
return i
else:
return -1
def strInStr2(A, B):
size = len(B)
for i in range(len(A)):
if A[i] == B[0]:
if A[i:i+size] == B:
return i
return -1
def strInStr3(A, B):
return A.index(B)
import timeit
setup = '''from __main__ import strInStr1, strInStr2, strInStr3, A, B'''
for f in ("strInStr1", "strInStr2", "strInStr3"):
result = timeit.timeit(f"{f}(A, B)", setup=setup)
print(f"{f}: ", result)
The results speak for themselves (time in seconds):
strInStr1: 15.809420814999612
strInStr2: 7.687011377005547
strInStr3: 0.8342400040055509
Here you have the live version

I'm brand new and working on Project Euler #2 in python

The goal is to sum up every even number up to 4 million.
I thought this would work but the program gets stuck running. Think it has to do with the if statement, but lost otherwise. Here's what I have.
list = []
a, b = 0, 1
while b <40:
if b%2 == 0:
list.append(b)
a, b = b, a+b
t=sum(list)
print(t)
This here is your biggest problem:
a, b = b, a+b
It has so much potential to mess up your loop! And like others mentioned it doesn't even update anything when b is odd, only when it is even, and then you're stuck.
Why not do this the simple way, with range:
mysum = sum([i for i in range(0, 40, 2)])
Will take care of everything with one line (and of course, replace 40 with 4,000,001 for your question, if you want to include the number 4,000,000 as well. If you just want everything up to it but not to include it, use just 4,000,000)
a, b = b, a+b
This line only runs if b % 2 == 0. I think you meant to run it every time. It should be indented one layer further out.
One can also use the mathematics rule where the sum of integers between 1 and n is equal to n*(n+1)/2. If we want to sum only even numbers, it is like considering only half the number to sum and multiply the result with two.
fSumEvenNumbers = lambda x: (x//2)*(x//2+1)
This would give
fSumEvenNumbers(40000000)
which is equivalent to
(2e7)**2 + 2e7
4e14 + 2e7
400000020000000

python find GCD recursively meet error

I have two pieces of python code finding two positive integers' GCD.
Here is the correct one:
def gcdRecur(a, b):
if b == 0:
return a
return gcdRecur(b, a%b)
Here is the one with bug:
def gcdRecur(a, b):
a = max(a, b)
b = min(a, b)
if b == 0:
return a
return gcdRecur(b, a%b)
It's easy to see the differences between these two pieces of code. And I know that there is no need to add
a = max(a, b)
b = min(a, b)
before the control flow. I can't find any logic mistakes in the latter code, but it print out the wrong result.
------use former code find GCD of 182 ans 224------
print out 14
------use former code find GCD of 182 ans 224------
print out 224(wrong answer)
So I guess it may be associated with the principle of recursion in python which I don't know at all. Can anyone help me and tell me what's going on T T.
Thank you.
The problem is when you call a = max(a,b) and b is the max value, the old a will be missing, and a will equal b which leads to gcd(b,b) == b

Getting two largest numbers from three numbers without using conditional statement or loop in python 3.5

Complete the function1() function which is passed three whole
numbers.The function returns the total of the two bigger numbers.
print()
print(1, function1(1, 2, 3))
print(2, function1(11, 12, 3))
print(3, function1(6, 2, 5))
output should be
1 5
2 23
3 11
This was the question. I try googling but all I have found was using conditional
statement or loop. I was wondering if there is other way to do this without using both? Reason being is that this question was on before the introduction of conditional statement and loop. I can advance my self-studying and do it however
there must be a reason why it poped up before we go onto the next chapter.
What do you reckon?.. (During self-studying for CS101) `
you could sort the tuple of the numbers and add the first 2 values:
def function1(a, b, c):
s = sorted((a, b, c), reverse=True)
return s[0] + s[1]
sorted starts with the smalles item normally that's why you need to set reverse=True.
or you could sum the three and subtract the minimal value:
def function1(a, b, c):
return sum((a, b, c)) - min(a, b, c)

Splitting a string in Python to 3 segments appointed to 3 variables depending on item count

I'm new to Python and struggling to solve the following issue the most Pythonic way.
I have a string (Example states given below) which needs to be split (.split('/', 2)) and appointed (up) to 3 variables (vars. a, b and c). The string is a URL which I need to split into 3 segments.
The string and its segments can be the following examples:
'seg_a/seb_b/the_rest' -> a = seg_a, b = seg_b, c = the_rest
'seg_a/the_rest' -> a = seg_a, b = None, c = the_rest
'seg_a' -> a = seg_a, b = None, c = None
Note: No obligation exists to have None value given if nothing else gets appointed. They simple may not exist (b in ex. 2, b and c in ex. 3).
If split results in 1 item, it's given to variable a.
If split results in 2 items, it's given to variable a and c
If split results in 3 items, then it's segments are given to variables a, b and c
I have found 2 methods achieving this, both seem not Pythonic, hence resulting in this question.
Method A:
Split.
Count.
Depending on count, appoint segments to variables with IF.. Elif.. Elif.. Else. statement
Method B:
Use list comprehension and nested Try-Except blocks. Ex:
try:
a, b, c = [i for i in to_split.split("/", 2)]
except ValueError:
try:
a, c = [i for i in to_split.split("/", 1)]
b = None
except ValueError:
a = to_split
b, c = None, None
My question (short):
What is the correct, Pythonic way of splitting this string to its
segments and appointing them to variables a, b and c?
I would do:
l = to_split.split("/", 2)
a, b, c = l + [None] * (3 - len(l))
IMHO, what is most Pythonic isn't what's most clever. If something is simple, concise, and comprehensible at a glance, then use it and get on with your day. If the rules you want to impose are
If split results in 1 item, it's given to variable a.
If split results in 2 items, it's given to variables a and c.
If split results in 3 items, it's given to variables a, b and c.
Then just implement that, Method A-style.
p = to_split.split("/", 2)
if len(p) == 1:
a, = p
elif len(p) == 2:
a, c = p
elif len(p) == 3:
a, b, c = p
else:
raise ValueError("could not parse {}".format(to_split))
I can read this and know exactly what it's doing. If there's a bug in there -- say I've swapped b and c when len(p) == 2 -- it's easy to fix once I see the problem.
It does seem a little strange that you're willing to let variables be undefined -- you must branch later to avoid getting a NameError, and that could, and probably should, be avoided with some refactoring. In my experience, something is probably a little off elsewhere. Even without changing anything else, I'd include a, b, c = [None]*3, myself.
One rule which helps keep code maintainable is that we should try to minimize the distance between what we would tell someone an algorithm is supposed to do and how we told the computer what to do. Here, since what you want to do is almost transcribable directly into Python, I'd just do that.
You could try:
a,b,c = (to_split("/",2) + [None]*3)[0:3]
However I agree with #DSM: the most pythonic way is not always the best approach to solve a problem. It could be ok at first, but a more verbose code works best in terms of readability.
That's one of the reasons I love Python: there are several ways to solve a problem, and it's up to the developer to choose the best according to his/her needs.

Categories