Longest Domino Sequence - python

Edit: New code. Both solutions were working perfectly, but for some reason did not improve my time results and that doesn`t make sense to me just yet.
Seeing my desperation, a friend PMed me his solution, which is working fine with the time given, but somehow fails on this specific input:
9
1 2 2 3 3 4 4 5
3 6 6 7 3 8 8 9 9 10
It gives "9" instead of "5". Any ideas why that could be?
maxNum = int(0)
idxArr = []
def ReadInput():
global array
global firstNum
arr = input().split()
firstNum = int(arr[0])
while int(arr[0]) * 2 + 1 > len(arr):
tempArray = input().split()
arr = arr + tempArray
iterator = int(0)
array = [0] * int(arr[0])
for i in range(1, int(arr[0]) * 2, 2):
tempArray = [0] * 3
tempArray[0] = int(arr[i])
tempArray[1] = int(arr[i + 1])
tempArray[2] = None
array[iterator] = tempArray
iterator+=1
def SortArray(array):
array.sort(key=lambda x: x[1])
array.sort(key=lambda x: x[0])
def MergeDominos(array):
tempNum = int(0)
for item in array:
if (item[2] == None):
iterator = tempNum
counter = int(0)
tempBool = False
try:
while item == array[iterator]:
if (tempBool):
array.pop(iterator)
counter += 1
else:
iterator += 1
counter += 1
tempBool = True
except IndexError:
True == True
if (counter % 2 == 1):
item[2] = counter
tempNum += 1
else:
tempItem = item.copy()
array.insert(tempNum + 1, tempItem)
array[tempNum + 1][2] = int(1)
item[2] = counter - 1
tempNum += 1
else:
tempNum += 1
def GetLengthOfArray(array):
counter = int(0)
for item in array:
counter += item[2]
return counter
def SwitchPlaces(item):
item[0], item[1] = item[1], item[0]
def GetMaxLength(array, tempArray, left, right):
global maxNum
# print("This is temp: ", tempArray)
for i in range(len(array)):
# print("Testing: ", array[i], "Iteration: ", i)
# print("IdxArr: ", idxArr)
if (len(array) <= len(idxArr)):
#print("BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE BREAKING HERE ")
break
if (i not in idxArr):
#print("Condition:")
if (left == array[i][0]):
#print("LL")
if (i in idxArr):
break
else:
idxArr.append(i)
SwitchPlaces(array[i])
if (len(array) >= len(idxArr)):
tempArray.insert(0, array[i])
if (GetLengthOfArray(tempArray) > maxNum):
maxNum = GetLengthOfArray(tempArray)
if (len(array) >= len(idxArr)):
GetMaxLength(array, tempArray, tempArray[0][0], tempArray[len(tempArray) - 1][1])
if (left == array[i][1]):
#print("LR")
if (i in idxArr):
break
else:
idxArr.append(i)
if (len(array) >= len(idxArr)):
tempArray.insert(0, array[i])
if (GetLengthOfArray(tempArray) > maxNum):
maxNum = GetLengthOfArray(tempArray)
if (len(array) >= len(idxArr)):
GetMaxLength(array, tempArray, tempArray[0][0], tempArray[len(tempArray) - 1][1])
if (right == array[i][0]):
#print("RL")
if (i in idxArr):
break
else:
idxArr.append(i)
if (len(array) >= len(idxArr)):
tempArray.append(array[i])
if (GetLengthOfArray(tempArray) > maxNum):
maxNum = GetLengthOfArray(tempArray)
if (len(array) >= len(idxArr)):
GetMaxLength(array, tempArray, tempArray[0][0], tempArray[len(tempArray) - 1][1])
if (right == array[i][1]):
#print("RR")
if (i in idxArr):
break
else:
idxArr.append(i)
SwitchPlaces(array[i])
if (len(array) >= len(idxArr)):
tempArray.append(array[i])
if (GetLengthOfArray(tempArray) > maxNum):
maxNum = GetLengthOfArray(tempArray)
if (len(array) >= len(idxArr)):
GetMaxLength(array, tempArray, tempArray[0][0], tempArray[len(tempArray) - 1][1])
#else:
# print("No condition BIG OOOF")
ReadInput()
SortArray(array)
MergeDominos(array)
for i in range(len(array)):
#print("iter num: ", i)
tempArray = []
idxArr = []
idxArr.append(i)
tempArray.append(array[i])
if (GetLengthOfArray(tempArray) > maxNum):
maxNum = GetLengthOfArray(tempArray)
GetMaxLength(array, tempArray, tempArray[0][0], tempArray[len(tempArray) - 1][1])
print(maxNum)
E1: The input is made in this weird way, because the first item of the list gives the number of dominoes, and also, the input can come in multiple rows and then I create list item pairs.
Example input:
5 1 2
1 2
2 3
2
17
2 17
And the dominoes are:
[('1','2'),('1','2'),('2','2'),('2','17'),('2','17')]
Expected result:
5
(3,2)-(2,1)-(1,2)-(2,17)-(17-2)

The following is a rewrite of your solution with one significant change:
if maximum == len(listOfDominos) + len(tempList):
break
This prevents the code from exploring any further once it has a maximum that it knows it can't improve on. For the example input you provided, it reduced the number of searches by 20x:
def find(listOfDominos, tempList):
maximum = len(tempList)
for currentDominoIndex, domino in enumerate(listOfDominos):
if maximum == len(listOfDominos) + len(tempList):
break # we can't do any better, so why try?
remainingDominos = listOfDominos[:currentDominoIndex] + listOfDominos[currentDominoIndex+1:]
if tempList:
backwardDomino = domino[::-1]
head, tail = tempList[0], tempList[-1]
if domino[1] == head[0]:
maximum = max(find(remainingDominos, [domino] + tempList), maximum)
elif backwardDomino[1] == head[0]:
maximum = max(find(remainingDominos, [backwardDomino] + tempList), maximum)
elif domino[0] == tail[1]:
maximum = max(find(remainingDominos, tempList + [domino]), maximum)
elif backwardDomino[0] == tail[1]:
maximum = max(find(remainingDominos, tempList + [backwardDomino]), maximum)
else:
maximum = max(find(remainingDominos, [domino]), maximum)
return maximum
listOfNumbers = input().split()
numberOfDominos = int(listOfNumbers.pop(0))
while numberOfDominos * 2 > len(listOfNumbers):
listOfNumbers += input().split()
listOfDominos = list(zip(listOfNumbers[0::2], listOfNumbers[1::2]))
print(find(listOfDominos, []))
Give this a try to see if it improves performance without introducing any bugs in the process.

Try this solution:
def solution(dominoes):
if len(dominoes) == 0:
return 0
def get_sequence(d, sol=None):
if sol is None:
sol = []
if len(d) == 0:
return
for i in range(len(d)):
rest = d[:i] + d[i+1:]
d1, d2 = d[i], d[i][::-1]
if d1 == d2:
if (not sol) or (sol[-1][1] == d1[0]):
yield sol + [d1]
yield from get_sequence(rest, sol + [d1])
else:
if (not sol) or (sol[-1][1] == d1[0]):
yield sol + [d1]
yield from get_sequence(rest, sol + [d1])
if (not sol) or (sol[-1][1] == d2[0]):
yield sol + [d2]
yield from get_sequence(rest, sol + [d2])
return(len(max(get_sequence(dominoes), key=len)))
dominoes = [('1','2'),('1','2'),('2','2'),('2','17'),('2','17')]
print(solution(dominoes))
Prints:
5

Related

Function not returning boolean [duplicate]

This question already has answers here:
Why Python recursive function returns None [duplicate]
(1 answer)
Recursive function does not return specified value
(2 answers)
Closed 1 year ago.
I have written a maze solver program. I want the PathFinder function to return True if a path is found and then print the path or else simply return False. But my program always keeps returning False even if a path is found. It would be great if you guys can help me figure this out.
def findPaths(m,path,i,j):
r,c = len(m), len(m[0])
if i == r-1 and j == c-1:
print(path)
return True
#explore
path.append(m[i][j])
# move down
if i != r-1 and m[i+1][j] == '↓ ':
findPaths(m,path,i+2,j)
#move up
if i < 0 and m[i-1][j] == '↑ ':
findPaths(m,path,i-2,j)
#move right
if j != c-1 and m[i][j+1] == '→':
findPaths(m,path,i,j+2)
#move left
if j > 0 and m[i][j-1] == '←':
findPaths(m,path,i,j-2)
path.pop()
def maze(r,c):
m = []
for i in range(r):
row = []
for j in range(1, c + (c)):
rand_num = str(randint(1, 99))
if j % 2 != 0:
if len(rand_num) == 1:
row.append(' ' + rand_num)
else:
row.append(rand_num)
else:
row.append('?')
m.append(row)
up_left_count = r * c // 3
down_right_count = r * c * 2 // 3
for v in range(r + (r - 1)):
vertical_lst = []
for each in range(1, c + c):
if each % 2 == 0:
vertical_lst.append(' ')
else:
vertical_lst.append('? ')
if v % 2 != 0:
m.insert(v, vertical_lst)
idx_i = []
idx_j = []
idx_v_i = []
idx_v_j = []
for i in range(len(m)):
for j in range(len(m[0])):
if i % 2 == 0 and j % 2 != 0:
idx_i.append(i)
idx_j.append(j)
for v_i in range(len(m)):
for v_j in range(len(m[0])):
if v_i % 2 != 0 and v_j % 2 == 0:
idx_v_i.append(v_i)
idx_v_j.append(v_j)
idx_i = list(set(idx_i))
idx_j = list(set(idx_j))
idx_v_i = list(set(idx_v_i))
idx_v_j = list(set(idx_v_j))
for count in range(up_left_count):
i_int = randint(0, len(idx_i) - 1)
j_int = randint(0, len(idx_j) - 1)
if m[i_int][j_int] != '←':
m[idx_i[i_int]][idx_j[j_int]] = '←'
for count_v in range(up_left_count):
i_v_int = randint(0, len(idx_v_i) - 1)
j_v_int = randint(0, len(idx_v_j) - 1)
if m[i_v_int][j_v_int] != '↑':
m[idx_v_i[i_v_int]][idx_v_j[j_v_int]] = '↑ '
for i in range(len(m)):
for j in range(len(m[0])):
if i % 2 == 0 and j % 2 != 0:
if m[i][j] == '?':
m[i][j] = '→'
for i in range(len(m)):
for j in range(len(m[0])):
if i % 2 != 0 and j % 2 == 0:
if m[i][j] != '↑ ':
m[i][j] = '↓ '
m[0][0] = "S"
m[-1][-1] = "D"
for i in range(len(m)):
for j in range(len(m[0])):
print(m[i][j], end=" ")
print()
path = []
return findPaths(m, path, 0,0)
if maze(5,6):
print('True')
else:
print('False')

Best way to run a function in main function when one of the parameters is not in the scope

Basically my brain is not working right now can't figure out the best way to resolve this error. builtins.NameError: name 'numIters' is not defined
I know this problem is that numIters is not defined in its scope but don't know the best solution to fix that.
Here is the bulk of my code
import random
alg = int(input("Select the sorting algorithm \n 1 - linear search \n 2 - binary search \nEnter Choice: "))
n = int(input("Choose the size of the list: "))
def main():
createList(n,alg)
print(runTest(values,n,alg))
printResults(alg,n,numIters)
#print(linearSearch(values,2))
#print(binarySearch(values, 2))
def createList(n,alg):
global values
values = []
random.seed(1456)
for j in range(n):
values.append(random.randint(0, 2*n))
while len(values) == n:
if alg == 2:
values.sort()
print(values)
return values
elif alg == 1:
print(values)
return values
def linearSearch(values, target):
numIters = 0
for i in range(len(values)):
numIters = numIters + 1
if values[i] == target:
return numIters
return -1
def binarySearch(values, target):
numIters = 0
start = 0
high = len(values) - 1
while start <= high:
middle = (start + high)//2
if values[middle] == target:
numIters = numIters + 1
return numIters
elif values[middle] > target:
numIters = numIters + 1
high = middle - 1
else:
numIters = numIters + 1
start = middle + 1
return -1
def runTest(values,n,alg):
if alg == 2:
count = 0
for j in range(n * 2):
count = count + 1
tgt = random.randint(0, 2*n)
binarySearch(values, tgt)
return count
elif alg == 1:
count = 0
for j in range(n * 2):
count = count + 1
tgt = random.randint(0, 2*n)
linearSearch(values, tgt)
return count
def printResults(alg, n, numIters):
avgIter = n / numIters
if alg == 2:
algType = Binary
if alg == 1:
algType = Linear
print("Results \n n = %d \n %s = %f.2 " % (n,algtype,avgIter))
main()
Thank you in advance for any help given as I am still trying to learn and understand how python works as a whole.
You need to return numIters so that you can pass it to the next function. It looks like it currently gets returned from binarySearch and linearSearch to runTest, but it gets discarded there; just bubble it up like this (I'm going to add type annotations and comments to help me keep track of what's going on):
from typing import List, Tuple
def runTest(values: List[int], n: int, alg: int) -> Tuple[int, int]:
"""Returns count, numIters"""
numIters = 0 # default value in case n is so small we don't iterate
if alg == 2:
count = 0
for j in range(n * 2):
count = count + 1
tgt = random.randint(0, 2*n)
numIters = binarySearch(values, tgt)
return count, numIters
elif alg == 1:
count = 0
for j in range(n * 2):
count = count + 1
tgt = random.randint(0, 2*n)
numIters = linearSearch(values, tgt)
return count, numIters
raise ValueError("alg needs to be 1 or 2!")
Now in your main() you can do:
def main():
createList(n, alg)
count, numIters = runTest(values, n, alg)
print(count)
printResults(alg, n, numIters)

string index out of range list iteration

I am fairly new to python, I am not sure on how to fix a index string out of range. it happens right after the while loop when I want to send mylist[i][0] to formatting function. Any pointer on my code in general would be awesome!
def formatting(str1):
if str1 == '?':
return True
else:
return False
while(i <= len(mylist)):
val = formatting(mylist[i][0])
if val == True:
str1 = mylist[i]
str2 = mylist[i+1]
i = i + 2
format_set(str1, str2)
else:
if format == True:
if (margin + count + len(mylist[i])) <= width:
if (i == (len(mylist)-1)):
list2.append(mylist[i])
print(" " * margin + " ".join(list2))
break
list2.append(mylist[i])
count += len(mylist[i])
i += 1
else:
print(" " * margin + " ".join(list2))
list2 = []
count = 0
else:
temp_margin = margin
temp_width = width
width = 60
margin = 0
if (margin + count + len(mylist[i])) <= width:
if (i == (len(mylist)-1)):
list2.append(mylist[i])
print(" " * margin + " ".join(list2))
margin = temp_margin
width = temp_width
break
list2.append(mylist[i])
count += len(mylist[i])
i += 1
else:
print(" " * margin + " ".join(list2))
list2 = []
count = 0
change
i <= len(mylist)
to
i < len(mylist)
In the last iteration of the while loop, i is referring to the last value. Hence,
str2 = mylist[i+1]
is trying to reference a string outside the allowed range and you get an error.
EDIT: Also, as Wcrousse mentioned, the while (i <= len(...)) should be changed to i < len(...) because indexes go from 0 - (length-1).

returning values in python

i have a code which looks like this
def monokode(b):
while f == 0:
if g[h]== b[i]:
i = i + 1
j = h - e
if j >= 100:
j = (e-h + len(g))*-1
elif j <= -100:
j = (e-h - len(g))*-1
if j < 10 and j >=0:
print 0,0,j,
elif j < 0:
j = j*-1
if j < 10:
print 1,0,j,
elif j >= 10 and j < 100:
print 1,j,
else:
print 1,j,
elif j >= 10 and j < 100:
print 0,j,
else:
print 0,j,
h = 0
if i >= len(b):
f = 1
else:
h=h+1
now, i want to make all the statements that print right now, return their value instead. but after some tries, i've realised that i don't know enough about the return statement to use it properly. how can i make the program return multiple values in a long line and then print them afterwards?
UPDATED ANSWER:
Okay as I understand the question you're wanting to make your function return multiple variables and then print them?
I agree with most of the other replies. Store the objects you want to print in a list then call
print ', '.join(list)
right before you return whatever values from the program:
like this:
def monokode(b):
printspool=[]
while f == 0:
if g[h]== b[i]:
i = i + 1
j = h - e
if j >= 100:
j = (e-h + len(g))*-1
elif j <= -100:
j = (e-h - len(g))*-1
if j < 10 and j >=0:
printspool.append([0,0,j])
elif j < 0:
j = j*-1
if j < 10:
printspool.append([1,0,j])
elif j >= 10 and j < 100:
printspool.append([1,j])
else:
printspool.append([1,j])
elif j >= 10 and j < 100:
printspool.append([0,j])
else:
printspool.append([0,j])
h = 0
if i >= len(b):
f = 1
else:
h=h+1
#Now here I'll print out everything contained in the printspooler list
for node in printspooler:
print ','.join(node)
#This is where you would
return Whatevervariable, Whatevervariable2, Whatevervariable3 etc...
Collect your values into a list instead, then return that list:
def yourfunction(your_arguments):
results = []
while f == 0:
if g[h]== b[i]:
i = i + 1
j = h - e
if j >= 100:
j = (e-h + len(g))*-1
elif j <= -100:
j = (e-h - len(g))*-1
if j < 10 and j >=0:
results.extend([0,0,j])
elif j < 0:
j = j*-1
if j < 10:
results.extend([1,0,j])
elif j >= 10 and j < 100:
results.extend([1,j])
else:
results.extend([1,j])
elif j >= 10 and j < 100:
results.extend([0,j])
else:
results.extend([0,j])
h = 0
if i >= len(b):
f = 1
else:
h=h+1
return results
You can use return and say many variable names...
return a, b, c
and what is returned is a tuple in the same order..
eg. return 1, 2, 3
will be (1, 2, 3)
and you can directly print call_fn() # if this returns those values
From what I understand, you can to store the values into a list:
def myfunc(…)
…
myList=[]
while f == 0:
if g[h]== b[i]:
i = i + 1
j = h - e
if j >= 100:
j = (e-h + len(g))*-1
elif j <= -100:
j = (e-h - len(g))*-1
if j < 10 and j >=0:
myList.extend([0,0,j])
elif j < 0:
j = j*-1
if j < 10:
myList.extend([1,0,j])
elif j >= 10 and j < 100: #this test
myList.extend([1,j])
else:
myList.extend([1,j])
elif j >= 10 and j < 100: #and this one
myList.extend([0,j])
else:
myList.extend([0,j])
h = 0
if i >= len(b):
f = 1
else:
h=h+1
return myList
and then print myFunc(…), or maybe something like
results = myFunc(…)
for r in results:
print r,
Edit: I've marked 2 tests that I think are unnecessary, since in the èlse part, you print the same thing

Python says: "IndexError: string index out of range."

I am making some practice code for a game similar to the board game, MasterMind-- and It keeps coming out with this error, and I can't figure out why it's doin it. Here's the code:
def Guess_Almost (Guess, Answer):
a = ''.join([str(v) for v in Answer])
g = str(Guess)
n = 0
am = 0
while n < 5:
if g[n] == a[0]:
am = am + 1
if g[n] == a[2]:
am = am + 1
if g[n] == a[3]:
am = am + 1
if g[n] == a[3]:
am = am + 1
n = n + 1
return(am)
Okay, the Guess is specified to be 4 integers, and the Answer is a list containing 4 numbers. They both have the same 'len' after the code, so i don't have a clue.
The point of this code is to turn the Answer into a string of 4 numbers, and see if any of those numbers match thoise of the guess, and return how many total matches there are.
See if this helps
def Guess_Almost (Guess, Answer):
a = ''.join([str(v) for v in Answer])
g = str(Guess)
n = 0
am = 0
if len(g) >= 5 and len(a) >=4:
while n < 5:
if g[n] == a[0]:
am = am + 1
if g[n] == a[2]:
am = am + 1
if g[n] == a[3]:
am = am + 1
if g[n] == a[3]:
am = am + 1
n = n + 1
return(am)

Categories