I tried solving the question below on codingbat:
"Given an array of integers, return True if the sequence of numbers 1, 2, 3 appears in the array somewhere".
This was my solution which returned with the error "index out of range":
def array123(nums):
for i in range(len(nums)):
if nums[i]==1 and nums[i+1]==2 and nums[i+2]==3:
return True
return False
This was Codingbat's solution:
def array123(nums):
for i in range(len(nums)-2):
if nums[i]==1 and nums[i+1]==2 and nums[i+2]==3:
return True
return False
I know I'm missing a trick here. Please could someone explain why I have to iterate over range(len(nums)-2)??
Thank you.
thats not exactly an amazing solution either, this would be proper:
def array123(nums):
for i in range(len(nums)-2):
if nums[i:i+3] == [1,2,3]:
return True
return False
print(array123([1,2,3]))
True
the main differences between your code and codingbat's is how the range is used
your range is the length of the list right? so since you are adding to the index by 2 at the highest case, we only should iterate until the length - 2, because anything over reaches past the highest index
They have used len(num) -2 , so that the num [i+2] points to the last element and not a index outside of the num
Thats because you are checking i th , i+1 th and i+2 th elements in the loop.
The requirement is to check 1,2,3 in the array anywhere.
and in python indices starting at zero, so range(len(num)-2) makes it to iterate over 0 to 7, if it is 10 elements array.
Related
Sorry for noob question. Just started learning coding with Python - beginners level.
Wasn't able to find in the net what I require.
Creating function to loop through the entire line, in order to find right combination - 7,8,9 - regardless of input length and of target position, and return 'true' if found. Wasn't able to devise the function correctly. Not sure how to devise function clearly and at all this far.
Your help is much appreciated.
This is what I came up with so far (not working of course):
def _11(n):
for loop in range(len(n)):
if n[loop]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
It always returns False. Tried with (*n) to no avail.
The answer offered by #Carson is entirely correct.
I offer this not really as an answer to the question but as an alternative and more efficient approach.
In OP's question he is looking for an occurrence of 3 consecutive values described by way of a list. Let's call that a triplet.
If we iterate over the input list one element at a time we create lots of triplets before comparing them.
However, we can make this more efficient by searching the input list for any occurrence of the first item in the target triplet. In that way we are likely to slice the input list far less often.
Here are two implementations with timings...
from timeit import timeit
def _11(n, t):
offset = 0
lt = len(t)
m = len(n) - lt
while offset < m:
try:
offset += n[offset:].index(t[0])
if n[offset:offset+lt] == t:
return True
offset += 1
except ValueError:
break
return False
def _11a(n, t):
for index in range(len(n) - len(t)):
if n[index:index + len(t)] == t:
return True
return False
n = [1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]
t = [7, 8, 9]
for func in _11, _11a:
print(func.__name__, timeit(lambda: func(n, t)))
Output:
_11 0.43439731000012216
_11a 1.8685798310000337
There are two mistakes with your code.
Indexing into a loop returns 1 element, not multiple. When you write n[loop], you're getting 1 value, not a list.
You shouldn't return false that early. Your code exits after the first step in the loop, but it should go through the entire loop before returning false.
Consider the following snippet:
def has_subarr(arr, subarr):
"""Tests if `subarr` exists in arr"""
for i in range(len(arr)):
if arr[i:i+len(subarr)] == subarr:
return True
return False
This code is more general than your example, it accepts the value to check for as another argument. Notice the use of : in the array access. This allows you to return multiple elements in an array. Also notice how the return False is only reached once the entire loop has completed.
First, n[loop] return a single element, not a sublist. You should use n[loop+3]. But this will introduce a problem where loop+3 exceeds the length of the list. So the solution may be:
def _11(n):
for loop in range(len(n)-3):
if n[loop:loop+3]==[7,8,9]:
return True
else:
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
Your actual code return during the first iteration. You only test once. You must modify the indentation as in:
def _11(n):
target = [7,8,9]
for index in range( len(n) - len(target)):
if n[index:index + len(target)] == [7,8,9]:
return True
return False
print(_11([1000,10,11,34,67,89,334,5567,6534,765,2,3,5,6,112,7,8,9,11111]))
You can try checking the str representation of the 2 lists:
import re
def _11(n):
if re.search("(?<![0-9-.'])7, 8, 9(?![0-9.])",str(n)):
return True
return False
print(_11([27,8,9]))
The Output:
False
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'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.
#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