I am trying to write a function that has only one argument, a list of positive integers.
It has to be recursive and find whether you can get from the start to the end while avoiding landing on 0s. It has to start at first value list[0] but you can jump by either the full amount or less.
For example
list1 = [3,1,2,0,4,0,1]
list2 = [3,2,1,0,2,0,2]
List 1 should return True as you can jump from 3 to 2 to 4 to 1.
List 2 should return False as it does not matter how you jump, you will land at the first 0.
Here is my attempt so far:
def check_level(level):
jump = level[0]
if level[-1] == 0:
return False
elif jump == 0:
return False
elif jump == 0:
return False
elif len(level) > 1:
if level[jump] > len(level):
return True
elif level[-1] == 0:
return False
elif level[0] != 0:
if level[jump] == 0:
level[0] -= 1
return check_level(level)
else:
jump_index = level.index(level[jump])
new_level = level[jump_index:]
return check_level(new_level)
else:
return True
It does not work with all examples and with others it comes up with an error:
if level[jump] > len(level):
TypeError: '>' not supported between instances of 'list' and 'int'```
I am out of ideas on how to approach this and whether my approach is failed from the start... I hate recursion, hence I need to practice it.
The general logic is:
"If you can jump to a True position, the current position is also True"
Implemented like this:
def checklevel(lst):
if not lst:
# no list is True (we are done)
return True
return any( checklevel(lst[i:]) for i in range(1,lst[0]+1))
list1 = [3,1,2,0,4,0,1]
list2 = [3,2,1,0,2,0,2]
assert checklevel(list1)
assert not checklevel(list2)
Note that this is a terrible solution for large lists, you should try a iterative dp-table in that case.
After advancing by a number of positions, you simply have to recurse with the rest of the list. Do it for distances from 1 to the value of the first element and you're done:
def jumpable(A):
if not A: return True # reaching end wins
return any(jumpable(A[i+1:]) for i in range(A[0])) # try all distances
ouput:
print(jumpable([3,1,2,0,4,0,1])) # True
print(jumpable([3,2,1,0,2,0,2])) # False
To avoid creating memory wasting temporary lists you can pass an index down (instead of a sublist) and use it as the starting point for the next level of recursion:
def jumpable(A,i=0):
if i>=len(A) : return True # reaching end
return any(jumpable(A,i+j+1) for j in range(A[i])) # try all distances
With a default value for i=0, you function still has only one parameter when called from the outside.
I am trying to find if a list is a strictly increasing sequenced if 1 and only 1 element from it is removed. This works for some lists but does not work for others when there isn't any apparent difference between the lists. And for large lists, it exceeds the execution time limit. This is my code:
def almostIncreasingSequence(sequence):
for i in range(len(sequence)):
new_seq = sequence.copy()
del new_seq[i]
if all(i < j for i, j in zip(new_seq, new_seq[1:])):
output = True
else:
output = False
return output
I'm creating a copy of the input list. Then, I'm removing the element i and then returning True or False depending on whether the list is a strictly increasing sequence. I am creating the copy of the list inside the for-loop to make sure that I am removing only one element. These are some of the test runs where the code does not return the appropriate value:
Input:
sequence: [10, 1, 2, 3, 4, 5]
Output: false
Expected Output: true
Input:
sequence: [1, 2, 5, 3, 5]
Output: false
Expected Output: true
And in this test case, the code exceeds the execution time limit:
Input:
sequence: [-9996, -9995, -9994, -9993, -9991, -9989, -9987, -9986, -9985, -9983, -9982, -9980, -9978, -9977, -9976, -9975, -9974, -9972, -9968, -9966, -9965, -9961, -9957, -9956, -9955, -9954, -9952, -9948, -9942, -9939, -9938, -9936, -9935, -9932, -9931, -9927, -9925, -9923, -9922, -9921, -9920, -9919, -9918, -9908, -9905, -9902, -9901, -9900, -9899, -9897, -9896, -9894, -9888, -9886, -9880, -9878, -9877, -9876, -9874, -9872, -9871, -9870, -9869, -9868, -9867, -9865, -9857, -9856, -9855, -9854, -9853, -9852, -9851, -9849, -9848, -9846, -9845, -9843, -9842, -9841, -9840, -9837, -9834, -9828, -9826, -9824, -9823, -9820, -9816, -9814, -9812, -9811, -9810, -9809, -9807, -9806, -9804, -9803, -9801, -9800]
Output: undefined
Expected Output: false
Your loop will always overwrite (with returning False or True) the previous result in each iteration. So it actually "forgets" about any violation in the previous iteration. Only the last iteration determines the output, so your algorithm is wrong.
Secondly, even if you would fix that error (by exiting the loop if the new list is not sorted), this algorithm represents a time complexity of O(n²), because in each iteration:
a copy of the list is made with .copy()
a del is performed, requiring a shift of all values that follow it
a new copy of the list is made with new_seq[1:]
zip is called, creating yet another list
all is called, iterating that new list
All of these actions are killing the performance.
Instead you should only perform one iteration over the list, and solve the problem without any nested iterations. One clue is that you don't actually have to perform the removal of the element. You only need to check the situation as if it were removed.
An efficient algorithm only needs to look at three values: the currently iterated value, and the two preceding values. If those three are not in order, you can determine which one should be removed, but only represent that removal in those three variables (keep the list untouched):
def almostIncreasingSequence(sequence):
beforePrev = prev = float('-inf')
allowExceptions = True
for curr in sequence:
if curr <= prev: # Order is not maintained:
if not allowExceptions: # It's not the first time
return False
allowExceptions = False
# Decide whether to skip the current or previous value
if curr > beforePrev:
prev = curr;
else: # Normal case: keep track of two preceding values
beforePrev, prev = prev, curr
return True
Explanation
Three list values are kept in separate memory during the traversal of the list: curr, prev and beforePrev. The latter two lag behind the curr value. So at each iteration, curr gets the current list value, and at the end of the iteration, we shift the values: beforePrev ← prev ← curr. So essentially, these three values correspond to the 3 most recently visited values -- at least when there is no anomaly in the list.
So let's say at a certain moment you find an anomaly: you find a position where curr <= prev, i.e. where the sequence is not strictly increasing; then it is clear one of the values has to be removed: either curr or prev should be removed to have any hope that the list can be "fixed".
It could be that the algorithm had already decided that a value had to be removed at an earlier iteration (allowExceptions is False): but we are only allowed to remove one value from the list, so in that case we decide that there is no solution and return False
But if this was the first time we got into this situation, then we should decide whether to identify curr or prev as offending value. We may assume that beforePrev and prev are in the correct order (we verified that in the preceding iteration), so there really are only two possibilities left for the relative ordering of beforePrev prev and curr: either curr > beforePrev, or not.
If curr > beforePrev, then those two are placed in a good ordering relative to each other, so if we would remove prev from between those two, we would restore that part of the list into an increasing ordering.
If curr <= beforePrev, then they are not in a good ordering relative to each other, so we should remove curr to restore the increasing ordering.
To save time we will not actually perform the removal of the chosen item from the list: we will just apply the result of that removal to the variables beforePrev, prev, and curr, so that in the next iteration they have values as if the list had one item removed:
As we removed an element, beforePrev should remain the same in the next iteration of the loop: so we don't touch its value, like we would normally do.
If we remove prev, then the new prev becomes what curr is now. If we remove curr, there is nothing to do: prev also remains the same for the next iteration, and curr will get its new value any way at the start of the next iteration.
Because we "deleted" an item we also set allowExceptions to False, so that we know that we are not allowed to perform a second deletion.
Remains to say that at the first iteration, we don't really have a beforePrev and prev, so we set them to -infinity, so that in a first iteration there will be no decision to delete yet.
You are returning the value of the last check, i.e. when you remove the last item in the list. Change it to return True in the first match or False if nothing matched
def almostIncreasingSequence(sequence):
for i in range(len(sequence)):
new_seq = sequence.copy()
del new_seq[i]
if all(i < j for i, j in zip(new_seq, new_seq[1:])):
return True
return False
Given a Tree T, sometimes binary or not, I need to retrieve the lowest Node that matches a criteria in each branch.
So, I need to retrieve a list (array) of those red marked nodes, where they label is equal to "NP" node.label() == 'NP'.
Actually I'm using NLTK Tree (nltk.tree.Tree) data structure, but you can post the pseudocode only, and I can implement it.
Here is the code that I've tried:
def traverseTree(tree):
if not isinstance(tree, nltk.Tree): return []
h = []
for subtree in tree:
if type(subtree) == nltk.tree.Tree:
t = traverseTree(subtree)
if subtree.label() == 'NP' and len(t) == 0: h.append(subtree)
return h
you have a conditional that if the there are no better candidates for your specification then append subtree, but what if len(t)>0? in that case you want to keep the nodes found in sub calls:
def traverseTree(tree):
if not isinstance(tree, nltk.Tree): return []
h = []
for subtree in tree:
if type(subtree) == nltk.tree.Tree:
t = traverseTree(subtree)
#RIGHT HERE!! need to extend by t or the other found nodes are thrown out
h.extend(t)
if subtree.label() == 'NP' and len(t) == 0:
h.append(subtree)
return h
Keep in mind that if t is always empty you would append all the valid nodes one level below, but any end-of-branch "NP" nodes will be found and returned in t so you want to pass them up a level in the recursion.
Edit: the only case where this would fail is if the top level node is "NP" and there are no sub-nodes of "NP" in which case tree should be added to h:
#after for loop has finished
if len(h) == 0 and tree.label() == "NP":
h.append(tree)
return h
edit2: if you add tree to h then the check for subtrees will never actually come true since they are checking the same node with the same conditionals just in differnt levels of recursion, so you can actually just write the function like this:
def traverseTree(tree):
if not isinstance(tree, nltk.Tree): return []
h = []
for subtree in tree:
#no need to check here as well as right inside the call
h.extend(traverseTree(subtree))
if tree.label() == 'NP' and len(h) == 0:
h.append(tree)
return h
I wrote a python code for Breadth search algorithm for 8 puzzle probelm. The states of the game are coded as a list of lists (two dimensional list). The goal is to reach [[1,2,3],[8,0,4],[7,6,5]] from a given state. The code output the path from a given state to the goal. It works fine but for this particular case [[0,1,2],[7,8,3],[6,5,4]] does not give the whole path rather it gives the last three states in the path.
Would you please try to point out the place of the bugs. Here is the code. Note The program starts from the statement:
"""
This program solves the 8 puzzel problems using Breadth First Search Algorithm.
"""
import copy
def successor(astate):
"""
This function takes an instance of the 8 puzzel problem and generates all the legal successors.
"""
up = copy.deepcopy(astate)
"""
important note:
I use [:] and list() to copy lists but it was not working fine, hence deecopy is used instead.
"""
down = copy.deepcopy(astate)
left = copy.deepcopy(astate)
right = copy.deepcopy(astate)
successors = []
for i in range(3):
for j in range(3):
if astate[i][j] == 0:
row = i
col = j
if row != 0:
dummy = up[row][col]
up[row][col] = up[row -1][col]
up[row-1][col] = dummy
successors.append(up)
if row != 2:
dummy = down[row][col]
down[row][col] = down[row+1][col]
down[row+1][col] = dummy
successors.append(down)
if col != 2:
dummy = right[row][col]
right[row][col] = right[row][col+1]
right[row][col+1] = dummy
successors.append(right)
if col != 0:
dummy = left[row][col]
left[row][col] = left[row][col-1]
left[row][col-1] = dummy
successors.append(left)
return successors
def puzzle(astate):
"""
This function takes a given instance of the 8 puzzel problem and returns the path to the goal where the goal is defined as below.
"""
goal = [[1,2,3],[8,0,4],[7,6,5]] #The goal state.
generation = [astate] #Nodes generated at each level.
tracking = {} #Track the path to the goal.
path = [] #The path from the root to the goal.
parent = generation.pop(0) #Takes the first element of the list!!
successors = successor(parent) #Generate successors.
key = str(parent) #keys odictionaries must be hashable and mutable. Lists are illegal keys.
tracking[key] = successors #Associate successors with their parent.
for asuccessor in successors:
generation.append(asuccessor) #Generate the first level.
if goal in generation: #if the goal is among the successors returns the path to it.
path.insert(0, key)
path.insert(0, goal)
return path
else:
while generation != []: #keep searching!
parent = generation.pop(0)
successors = successor(parent) #generate successors
key = str(parent)
tracking[key] = successors
if goal in [astate for astate in successors]: #if the goal is among the successors backtrack its path.
path.insert(0, str(goal)) #Just because path contains states as strings!!
path.insert(0, key)
for key in tracking.keys():
for value in tracking.get(key):
if str(parent) == str(value): #If the current (parent) is among the values of (key) then (key) is its parent.
path.insert(0, key)
parent = key
break
return path
else: #keep searching
for asuccessor in successors:
if asuccessor not in generation: #If the current successors is already generated do not add it.
if str(asuccessor) not in tracking.keys(): #If the successor is a previous parent do not add it.
generation.append(asuccessor)
return
I am having some trouble in determining the distance of each node from the start node, or rather getting any information back at all.
I get no output from my function, attached in the following link.
#Values to assign to each node
class Node:
distFromSource = infinity
previous = invalid_node
visited = False
#for each node assign default values
def populateNodeTable(network):
nodeTable = []
index = 0
f = open('network.txt', 'r')
for line in f:
node = map(int, line.split(','))
nodeTable.append(Node())
print "The previous node is " ,nodeTable[index].previous
print "The distance from source is " ,nodeTable[index].distFromSource
index +=1
nodeTable[startNode].distFromSource = 0
return nodeTable
#calculate the distance of each node from the start node
def tentativeDistance(currentNode, nodeTable):
nearestNeighbour = []
for currentNode in nearestNeighbour:
currentDistance == currentNode.distFromSource + [currentNode][nearestNeighbour] #gets current distance from source
print "The current distance"
if currentDistance != 0 & currentNode.distFromSource < Node[currentNode].distFromSource:
nodeTable[currentNode].previous = currentNode
nodeTable[currentNode].length = currentDistance
nodeTable[currentNode].visited = True
nodeTable[currentNode] +=1
nearestNeighbour.append(currentNode)
for currentNode in nearestNeighbour:
print nearestNeighbour
return nearestNeighbour
My logic is, at least in my mind, correct; however, I don't get as much as an error message when the code is run.
You're setting nearestNeighbour to be an empty list, and then you're looping over it with for currentNode in nearestNeighbour -- which does nothing, because the list is empty -- and then you're returning from the function.
(I assume tentativeDistance is the function you're calling and seeing nothing from.)
You should rethink your algorithm design. Try looking up a pseudocode definition of Dijkstra's algorithm and implementing that in Python. In particular, you should think about the control flow in your program.
You might want to have a look at this cookbook recipe for a Python implementation of Dijkstra and see if you can understand it.