Here's the problem.
This is part of the List-2
Medium python list problems -- 1 loop.
Given an array of ints, return True if the array contains a 2 next to a 2 somewhere.
has22([1, 2, 2]) → True
has22([1, 2, 1, 2]) → False
has22([2, 1, 2]) → False
I was getting the error "list index is out of range" at first
I know where I was going wrong on line 4 of the original problem because once it is at the last number in the list it cannot add one anymore.
I have provided my original code below. The first code block was when I was getting the error "index out of range". The second solution works but I am wondering if there is a cleaner way of writing it.
Also on CodingBat when I run my solution it says "Other Tests" Failed at the bottom but no example I'm not sure what that means.
Thanks
Here's my code block - FIRST TRY:
def has22(nums):
for i in range(len(nums)):
first = nums[i]
second = nums[i+1]
if first == second:
return True
MY SOLUTION:
def has22(nums):
size = len(nums)
for i in range(len(nums)):
first = nums[i]
if size >= i+2:
second = nums[i+1]
if first == second:
return True
return False
So if the question is whether the solution can be written cleaner, I think something like this should work:
def has22(nums):
return (2, 2) in zip(num, num[1:])
and it looks pretty clean.
A little bit of explanation - zip creates pairs of values from 2 lists, so I just slice the input list into 2, where in the second list I omit the first element. Then I simply check whether tuple 2, 2 exists in the zipped pairs.
BTW I just noticed a bug in your solution - it returns True for input e.g. [2, 1] (basically any input, where 2 is second to last. So to fix this bug, and preserve the original "idea" of your solution, you could write it like this:
def has22(nums):
for i, el in enumerate(nums):
if el == 2 and i + 1 < len(nums) and nums[i + 1] == 2:
return True
return False
enumerate is the preferred way of iterating through a list with indices.
Related
Given the following problem:
You are given an integer array nums. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.
Return true if you can reach the last index, or false otherwise.
Example 1:
Input: nums = [2,3,1,1,4]
Output: True
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [3,2,1,0,4]
Output: False
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
I am trying to come up with a recursive solution. This is what I have so far. I am not looking for the optimal solution. I am just trying to solve using recursion for now. If n[i] is 0 I want the loop to go back to the previous loop and continue recursing, but I can't figure out how to do it.
def jumpGame(self, n: []) -> bool:
if len(n) < 2:
return True
for i in range(len(n)):
for j in range(1, n[i]+1):
next = i + j
return self.jumpGame(n[next:])
return False
If you want to do recursively and you said no need to be optimal ( so not memoized ), you could go with the below method. You don't need nested loops.
Also no need to explore all paths, you could optimize by looking at the step that you are going by checking i + (jump) < n
def jumpGame(a, i):
if i > len(a) - 1:
return False
if i == len(a) - 1:
return True
reached = False
for j in range(1, a[i] + 1):
if i + j < len(a):
reached = jumpGame(a, i + j)
if reached:
return True
return reached
print(jumpGame([2, 3, 1, 1, 4], 0))
print(jumpGame([3,2,1,0,4], 0))
True
False
When considering recursive solutions, the first thing you should consider is the 'base case', followed by the 'recursive case'. The base case is just 'what is the smallest form of this problem for which I can determine an answer', and the recursive is 'can I get from some form n of this problem to some form n - 1'.
That's a bit pedantic, but lets apply it to your situation. What is the base case? That case is if you have a list of length 1. If you have a list of length 0, there is no last index and you can return false. That would simply be:
if len(ls) == 0:
return False
if len(ls) == 1:
return True
Since we don't care what is in the last index, only at arriving at the last index, we know these if statements handle our base case.
Now for the recursive step. Assuming you have a list of length n, we must consider how to reduce the size of the problem. This is by making a 'jump', and we know that we can make a jump equal to a length up to the value of the current index. Then we just need to test each of these lengths. If any of them return True, we succeed.
any(jump_game(n[jump:] for jump in range(1, n[0] + 1)))
There are two mechanisms we are using here to make this easy. any takes in a sequence and quits as soon as one value is True, returning True. If none of them are true, it will return False. The second is a list slice, n[jump:] which takes a slice of a list from the index jump to the end. This might result in an empty list.
Putting this together we get:
def jump_game(n: list) -> bool:
# Base cases
if len(n) == 0:
return False
if len(n) == 1:
return True
# Recursive case
return any(jump_game(n[jump:]) for jump in range(1, n[0] + 1))
The results:
>>> jump_game([2,3,1,1,4])
True
>>> jump_game([3,2,1,0,1])
False
>>> jump_game([])
False
>>> jump_game([1])
True
I'm trying to lay out the rigorous approach here, because I think it helps to clarify where recursion goes wrong. In your recursive case you do need to iterate through your options - but that is only one loop, not the two you have. In your solution, in each recursion, you're iterating (for i in range(len(n))) through the entire list. So, you're really hiding an iterative solution inside a recursive one. Further, your base case is wrong, because a list of length 0 is considered a valid solution - but in fact, only a list of length 1 should return a True result.
What you should focus on for recursion is, again, solving the smallest possible form(s) of the problem. Here, it is if the list is one or zero length long. Then, you need to step each other possible size of the problem (length of the list) to a base case. We know we can do that by examining the first element, and choosing to jump anywhere up to that value. This gives us our options. We try each in turn until a solution is found - or until the space is exhausted and we can confidently say there is no solution.
#here is the code
def has_33(nums):
for i in range(0,len(nums)-1):
if nums[i:i+2]==[3,3]:
return True
return False
nums = [1,2,3,3]
print(has_33(nums))
questions:
why the code used len(nums)-1 in second line?(why used -1 ?)
in the 3rd line why do they used [i:i+2]==[3,3] and how does this code perform ?
please let me know ,
i am basically a noob in coding right now please help me to under stand how this code works
If you're looking for two elements in a row, there's no point in checking the last element of the list, since there's nothing after it. So the loop stops at the 2nd-to-last index.
nums[i:i+2] returns a slice of the list from element i to element i+1. Those are 2 consecutive elements. Then it compares this to [3, 3] to see if that pair of elements are two 3's next to each other.
Because a list of the length n has only n-1 pairs (for example, [1,2,3,4] has [1,2], [2,3] and [3,4])
Beacuse list[x:y] does not return element y of the list.
The following code is simple and should work for what you want to do.
a=[0, 1, 2, 0, 3]
def has_33():
last_i = 0
for i in a:
if last_i==3 and i==3:
return True
if i==3:
last_i = 3
return False
print(has_33())
Also works in different combinations of ...3,3...
Given an array of ints, return True if .. 1, 2, 3, .. appears in the array somewhere.
def array123(nums):
for i in nums:
if nums[i:i+3] == [1,2,3]:
return True
return False
Coding bat problem
my code is satisfying all the test cases except for nums=[1,2,3]
can someone tell me whats wrong with my code
It should be like this.
def array123(nums):
for i in range(len(nums)):
if nums[i:i+3] == [1,2,3]:
return True
return False
Try this. Hope this helps. :)
Your code is not completely right. You're slicing the list with the items in the list, not with indices. Luckily, this did not throw any error because the items in the list are within the bounds of the list's indices or rather slicing does not raise errors, when done correclty, irrespective of start and/or stop indices.
You can use range(len(...)) to generate the indices, and you may stop the search at len(nums) - len(sublist), so you don't check for slices less than the length of the sublist. This comes more handy as the length of the sublist gets larger.
def array123(nums, sublist):
j = len(sublist)
for i in range(len(nums)-j):
if nums[i:i+j] == sublist:
return True
return False
# Call function
array123(nums, [1,2,3])
Useful reference:
Explain Python's slice notation
You're getting wrong result because you're iterating on the value of elements not on the index of elements of elements. Try following code
def array123(nums):
for i in range(len(nums)-2):
if nums[i:i+3] == [1,2,3]:
return True
return False
And remember to give the end index of list (range(len(nums)-2)) because suppose if length of your array is 4 then (range(len(nums)-2)) will be
(range(2)) = [0,1]
So the loop will iterate for 0,1 as starting index
I am learning the recursive functions. I completed an exercise, but in a different way than proposed.
"Write a recursive function which takes a list argument and returns the sum of its integers."
L = [0, 1, 2, 3, 4] # The sum of elements will be 10
My solution is:
def list_sum(aList):
count = len(aList)
if count == 0:
return 0
count -= 1
return aList[0] + list_sum(aList[1:])
The proposed solution is:
def proposed_sum(aList):
if not aList:
return 0
return aList[0] + proposed_sum(aList[1:])
My solution is very clear in how it works.
The proposed solution is shorter, but it is not clear for me why does the function work. How does if not aList even happen? I mean, how would the rest of the code fulfill a not aList, if not aList means it checks for True/False, but how is it True/False here?
I understand that return 0 causes the recursion to stop.
As a side note, executing without if not aList throws IndexError: list index out of range.
Also, timeit-1million says my function is slower. It takes 3.32 seconds while the proposed takes 2.26. Which means I gotta understand the proposed solution.
On the call of the function, aList will have no elements. Or in other words, the only element it has is null. A list is like a string or array. When you create a variable you reserve some space in the memory for it. Lists and such have a null on the very last position which marks the end so nothing can be stored after that point. You keep cutting the first element in the list, so the only thing left is the null. When you reach it you know you're done.
If you don't use that condition the function will try to take a number that doesn't exist, so it throws that error.
You are counting the items in the list, and the proposed one check if it's empty with if not aList this is equals to len(aList) == 0, so both of you use the same logic.
But, you're doing count -= 1, this has no sense since when you use recursion, you pass the list quiting one element, so here you lose some time.
According to PEP 8, this is the proper way:
• For sequences, (strings, lists, tuples), use the fact that empty
sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
Here is my amateur thougts about why:
This implicit check will be faster than calling len, since len is a function to get the length of a collection, it works by calling an object's __len__ method. This will find up there is no item to check __len__.
So both will find up there is no item there, but one does it directly.
not aList
return True if there is no elements in aList. That if statement in the solution covers edge case and checks if input parameter is not empty list.
For understand this function, let's run it step by step :
step 0 :
L=[0,1,2,3,4]
proposed_sum([0,1,2,3,4])
L != []
return l[0] + proposed_sum([1,2,3,4])
step 1 calcul proposed_sum([1,2,3,4]):
proposed_sum([1,2,3,4])
L != []
return l[0] + sum([2,3,4])
step 2 calcul proposed_sum([2,3,4]):
proposed_sum([2,3,4])
L != []
return l[0] + sum([3,4])
step 3 calcul proposed_sum([3,4]):
proposed_sum([3,4])
L != []
return l[0] + sum([4])
step 4 calcul proposed_sum([4]):
proposed_sum([4])
L != []
return l[0] + sum([])
step 5 calcul proposed_sum([]):
proposed_sum([])
L == []
return 0
step 6 replace:
proposed_sum([0,1,2,3,4])
By
proposed_sum([]) + proposed_sum([4]) + proposed_sum([3,4]) + proposed_sum([2,3,4]) + proposed_sum([1,2,3,4])+ proposed_sum([0,1,2,3,4])
=
(0) + 4 + 3 + 2 + 1 + 0
Python considers as False multiple values:
False (of course)
0
None
empty collections (dictionaries, lists, tuples)
empty strings ('', "", '''''', """""", r'', u"", etc...)
any other object whose __nonzero__ method returns False
in your case, the list is evaluated as a boolean. If it is empty, it is considered as False, else it is considered as True. This is just a shorter way to write if len(aList) == 0:
in addition, concerning your new question in the comments, consider the last line of your function:
return aList[0] + proposed_sum(aList[1:])
This line call a new "instance" of the function but with a subset of the original list (the original list minus the first element). At each recursion, the list passed in argument looses an element and after a certain amount of recursions, the passed list is empty.
I'm going through some of the exercises on codingbat.com. The exercise I'm stuck on is this:
"Given an array of ints, return True if 6 appears as either the first or last element in the array. The array will be length 1 or more.
first_last6([1, 2, 6]) → True
first_last6([6, 1, 2, 3]) → True
first_last6([13, 6, 1, 2, 3]) → False"
Here is what I put for my answer. I know it's incorrect, but I'm not sure what I did wrong.
def first_last6(nums):
if nums[0] == 6 or nums[len(nums)-1] == 6:
return True
else:
return False
Your solution will actually work. Here is a slightly better one though:
def first_last6(nums):
return nums[0] == 6 or nums[-1] == 6
nums[-1] gives you the last element
for find last index in python you can use -1 as index of list.
you just need to change nums[-1] instead of nums[len(nums)-1]
def first_last6(nums):
if nums[0] == 6 or nums[-1] == 6:
return True
else:
return False
Update:
After reading below comments, 6 == llist[0] or 6 == llist[-1] will work more efficiently than creating a tuple.
Just do 6 in (llist[0],llist[-1]), you dont need to write a function for that.
L[0]==6 or L[-1]==6
L[0] checks the element at the 0-th index, i.e. the first element
L[-1] checks the element at the -1-th index, i.e. the last element. Note that this is equivalent to checking L[len(L)-1]
If you want to make it nice and scalable, you might consider doing this:
CHECK_INDICES = (0,-1)
any(L[i]==6 for i in CHECK_INDICES)
In Python3 you can also get the first and last like this. A ValueError is thrown if there is only a single item in nums
def first_last6(nums):
first, *middle, last = nums
return first == 6 or last == 6