I need a little help, a have a list of integers - the difference between the consecutive elements is constant, but the list is unsorted and one element is missing. The function takes a list as an input, the output is an integer (the missing one).
I wrote this code:
def missing_number(lst):
lst.sort()
diff = lst[1] - lst[0]
for i in range(len(lst)-1):
if lst[i+1] - lst[i] != diff:
return int(lst[i] + diff)
It's working for this case: assert missing_number([1, 4, 2, 5]) == 3, but I can't make it work for a case like this: assert missing_number([2, 6, 8]) == 4 - the difference is more than 1 digit - it's returning 10.
A linear time solution: Compute the sum you'd expect if the number weren't missing, and subtract the actual sum:
def missing_number(lst):
expect = (min(lst) + max(lst)) * (len(lst) + 1) // 2
return expect - sum(lst)
The expected full sum is the average (which is (min+max)/2) multiplied by the number of numbers (which is len+1). I postpone the division until the end since min+max might be odd.
Yours fails the example [2, 6, 8] because you compute diff = 4, but it should be 2. You can't just always use lst[1] - lst[0]. You could for example use (lst[-1] - lst[0]) // len(lst) instead.
It doesn't like your code is not working as expected for difference is more than 1 digit.
It is purely because of sequence.
If you try the differ sequence with more with your code, it gonna definitely work. Eg:assert missing_number([2, 4, 8]) == 6
So you can not take difference between 1st 2 numbers. You have to take the minimum difference, so you can check by comparing difference with next 2 numbers & take the smallest.
You can try:
def missing_number(lst):
lst.sort()
final_diff = 0
diff0 = lst[1] - lst[0]
diff1 = lst[2] - lst[1]
if diff0 < diff1:
final_diff = diff0
else:
final_diff = diff1
for i in range(len(lst)-1):
if lst[i+1] - lst[i] != final_diff:
return int(lst[i] + final_diff)
print(missing_number([2, 6, 8]))
output:
4
Related
I am getting a IndexError: list index out of range error. I'm not sure why. Any advice?
The code is trying to see if a list of numbers is an arithmatic progression, in this case every number is added by 2.
def is_arith_progession(num_list):
delta = num_list[1] - num_list[0]
for num in num_list:
if not (num_list[num + 1] - num_list[num] == delta):
return False
else:
return True
print(is_arith_progession([2, 4, 6, 8, 10]))
You are trying access 5th element of num_list array in the second iteration of for loop. After the first iteration num becomes 4, so program crashes when it tries to evaluate num_list[num + 1].
num variable holds the actual element in the list. It is not index to element.
To iterate over indices, you may try for num in range(len(num_list) - 1) which should solve the issue. (Note -1 in the paranthesis)
This:
for num in num_list:
if not (num_list[num + 1] - num_list[num] == delta):
return False
almost certainly doesn't do what you think it does. When you define for num in num_list:, this means that num is an item from the list num_list. num is NOT an index. So, if your list is [2, 4, 6, 8, 10], you go out of bounds when num is 4 (i.e. the second item in your list), because your input list is only length 5 and you try to access index num+1, which is 5 (indexes are 0 based, so 5 is out of bounds)
You probably want something like this:
# Start at index 1, or you'll always return false since delta == index1 - index0
for index in range(1, len(num_list)-1):
if not (num_list[num + 1] - num_list[num] == delta):
return False
or the more pythonic (note there are no indices):
# Again start at index1, zip will handle the edge case of ending nicely so we don't go OB
for num, next_num in zip(num_list[1:], num_list[2:]):
if not (next_num - num == delta):
return False
You are iterating over the values, not the indexes of the array. So, num_list[num] can be out of range. Since you refer to the i+1 element, iterate up to i < n-1
for i, _ in enumerate(num_list[:-1]):
if num_list[i+1] - num_list[i]...
2 things:
num is an element of num_list, not just an index. Getting an index would be for num in range(len(num_list)):, you're effectively calling num_list[num_list[i]];
Even if it was an index, for the last index num in array you are calling numlist[num+1], which is out of array bounds as num is already last;
Do for INDEX in range(len(num_list)-1): and if not (num_list[INDEX + 1] - num_list[INDEX] == delta):. That should do it.
I am trying to solve a problem where:
Given an array of n integers nums and a target, find the number of
index triplets i, j, k with 0 <= i < j < k < n that satisfy the
condition nums[i] + nums[j] + nums[k] < target.
For example, given nums = [-2, 0, 1, 3], and target = 2.
Return 2. Because there are two triplets which sums are less than 2:
[-2, 0, 1] [-2, 0, 3]
My algorithm: Remove a single element from the list, set target = target - number_1, search for doublets such that number_1 + number _2 < target - number_1. Problem solved.
The problem link is https://leetcode.com/problems/3sum-smaller/description/ .
My solution is:
def threeSumSmaller(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums = sorted(nums)
smaller = 0
for i in range(len(nums)):
# Create temp array excluding a number
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
# Sort the temp array and set new target to target - the excluded number
l, r = 0, len(temp) -1
t = target - nums[i]
while(l<r):
if temp[l] + temp[r] >= t:
r = r - 1
else:
smaller += 1
l = l + 1
return smaller
My solution fails:
Input:
[1,1,-2]
1
Output:
3
Expected:
1
I am not getting why is the error there as my solution passes more than 30 test cases.
Thanks for your help.
One main point is that when you sort the elements in the first line, you also lose the indexes. This means that, despite having found a triplet, you'll never be sure whether your (i, j, k) will satisfy condition 1, because those (i, j, k) do not come from the original list, but from the new one.
Additionally: everytime you pluck an element from the middle of the array, the remaining part of the array is also iterated (although in an irregular way, it still starts from the first of the remaining elements in tmp). This should not be the case! I'm expanding details:
The example iterates 3 times over the list (which is, again, sorted and thus you lose the true i, j, and k indexes):
First iteration (i = 0, tmp = [1, -2], t = 0).
When you sum temp[l] + temp[r] (l, r are 0, 1) it will be -1.
It satisfies being lower than t. smaller will increase.
The second iteration will be like the first, but with i = 1.
Again it will increase.
The third one will increase as well, because t = 3 and the sum will be 2 now.
So you'll count the value three times (despite only one tuple can be formed in order of indexes) because you are iterating through the permutations of indexes instead of combinations of them. So those two things you did not take care about:
Preserving indexes while sorting.
Ensuring you iterate the indexes in a forward-fashion only.
Try like this better:
def find(elements, upper_bound):
result = 0
for i in range(0, len(elements) - 2):
upper_bound2 = upper_bound - elements[i]
for j in range(i+1, len(elements) - 1):
upper_bound3 = upper_bound2 - elements[j]
for k in range(j+1, len(elements)):
upper_bound4 = upper_bound3 - elements[k]
if upper_bound4 > 0:
result += 1
return result
Seems like you're counting the same triplet more than once...
In the first iteration of the loop, you omit the first 1 in the list, and then increase smaller by 1. Then you omit the second 1 in the list and increase smaller again by 1. And finally you omit the third element in the list, -2, and of course increase smaller by 1, because -- well -- in all these three cases you were in fact considering the same triplet {1,1,-2}.
p.s. It seems like you care more about correctness than performance. In that case, consider maintaining a set of the solution triplets, to ensure you're not counting the same triplet twice.
There are already good answers , Apart that , If you want to check your algorithm result then you can take help of this in-built funtion :
import itertools
def find_(vector_,target):
result=[]
for i in itertools.combinations(vector_, r=3):
if sum(i)<target:
result.append(i)
return result
output:
print(find_([-2, 0, 1, 3],2))
output:
[(-2, 0, 1), (-2, 0, 3)]
if you want only count then:
print(len(find_([-2, 0, 1, 3],2)))
output:
2
I have,
def geometric(lst):
'checks whether the integers in list lst form a geometric sequence'
for i in range(1, len(lst) - 1):
if lst[i] * 2 == "don't know what to check here":
return True
else:
return False
I'm not sure how to apply that to check if all the indices. Would prefer this done within a for-loop. any help would be appreciated!
I think this works:
def geometric(lst):
for i in range(len(lst) - 2):
if lst[i] * lst[i + 2] != lst[i + 1] ** 2:
return False
return True
This is based on the idea that for any three consecutive terms a, b, c, the ratio between the first two must equal the ratio between the last two, i.e. b/a = c/b. Rearranging this gives a * c == b ** 2. It's much better to use the form without division, because division introduces rounding errors. This function even works if the common ratio is not an integer (e.g. [4, 6, 9]).
Edit
The above answer does not handle lists containing 0 correctly.
A correct version is:
def geometric(lst):
for i in range(len(lst) - 2):
if lst[i] * lst[i + 2] != lst[i + 1] ** 2:
return False
for i in range(len(lst) - 1):
if lst[i] == 0 and lst[i + 1] != 0:
return False
return True
This returns True for [1, 0, 0] (common ratio 0) but False for [0, 0, 1]. The original version returned True for both.
It may be better to disallow common ration 0. This would mean changing the second loop to return False for any list of length 2 or more containing 0.
As sam2090 has pointed out, the right side of the condition in line 4 has been left empty. If the common ratio of the geometric sequence is 2 (maybe it's something that you would actually want to pass as a parameter of the function), then the expression should be:
if lst[i] == lst[i-1] * 2
The left-hand side of the statement refers to the current number in the itertion (i), while the right-hand side of the statement refers to the previous number (i-1) and multiplies its value by 2.
Also, in the foor loop, be sure you iterate until the last element in the list, so you should write:
for i in range(1, len(lst)):
and not
for i in range(1, len(lst) - 1):
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am brand new to python. I have been learning this on my own. I always make sure to exhaust every resource before asking a question on here.
but I will show you two sets of code. One does what I want, the other doesn't the only difference that appears to me, is how the ranges are set up. I don't understand the significance of this difference. Could someone please explain?
Thank you.
Code that works
def geometric(lst):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = lst[1]/lst[0]
for i in range(1, len(lst)-1):
if lst[i+1]/lst[i] != ratio:
return False
return True
**code that doesn't **
def geometric(integerList):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = integerList[1]/integerList[0]
for i in range (integerList[0], len(integerList))
if lst[i+1]/lst[i] != ratio:
return False
return True
In the first case, range(1, len(lst)-1) is a list
1, 2, 3, ..., len(lst)-1
In the second case, it depends on the value of the first list element. If integerList[0] is 3, then range() is
3, 4, 5, ..., len(lst)-1
and the first call of the if() statement compares integerList[4] / integerList[3] and ignores the first three elements in the list. So, the code only works, if integerList[0] == 1
However, there are two further pitfalls:
range() only takes integers as elements. If the first element is a float, pyhon will throw an error.
If the ratio always is an integer, you can compare the ratios for equality, as you do. But if ratio is a floating value, you can get into trouble: Though two ratios are mathematically equal, a computer (due to its floating point arithmetic) may calculate slightly different values. It is better to use
import math
...
if (math.fabs(lst[i+1]/lst[i] - ratio) < smallNumber)
where smallNumer is a very small number suitable for you.
By the way: In your second code, you use lst[] , but I guess, it was just a typo.
As Noelkd said, the range in your second code block starts with the value of the first element of the list, not its position.
If my list is the geometric sequence (1, 2, 4, 8, 16), your first block's range is
range(1, len(lst)-1) =
range(1, 5 - 1) =
range(1, 4) =
[1, 2, 3]
and your second block's range is
range(integerList[0], len(integerList)) =
range(1, 5) =
[1, 2, 3, 4]
This difference gets even weirder if my sequence doesn't start with 1, such as for the sequence (3, 9, 27):
First block's range is
range(1, len(lst)-1) =
range(1, 3 - 1) =
range(1, 2) =
[1]
and second block's range is
range(integerList[0], len(integerList)) =
range(3, 3) =
[]
for i in range(1, len(lst)-1):
...
This code first creates a list containing the numbers [1,2,3,...,len(lst)-1] and then loops over these values by setting i to a value in this list on every iteration.
for i in range (integerList[0], len(integerList))
This code actually creates a list containing the numbers:
[integerList[0],integerList[0] + 1,integerList[0] + 2,...,len(integerList)]
Here you're starting the range at integerList[0] not it's index. And if integerList[0] is bigger than len(integerList) you'll get an array with no values []
You also then try to use lst in the second function when really you're looking for integerList
This should help you understand what's happening:
>>> x = [2,4,5,6,7,8]
>>> for i in range(1,len(x)):
... print x[i]
...
4
5
6
7
8
So that's printing from the second to the last item.
>>> for i in range(x[0],len(x)):
... print x[i]
...
5
6
7
8
The second block is starting from x[0] which is 2 so from the third element to the last element.
Unless integerList[0] is always equal to 1 then you will not get the same range as range(1, len(lst)-1) which starts at 1, if integerList[0] == 5 your range will be range(5, len(integerList)) so you would miss elements from indexes 1 - 4 that you get in your first block of code and it would also throw an index error as lst[i+1] would be 1 index past the end of the list:
It would also be better to use enumerate:
def geometric(lst):
'checks whether the integers in list lst form a geometric sequence'
if len(lst) <= 1:
return True
ratio = lst[1] / lst[0]
for ind, ele in enumerate(lst[1:-1]):
if lst[ind+1] / ele != ratio:
return False
return True
In [4]: lst = ["foo","bar","foobar"]
In [5]: for ind, ele in enumerate(lst):
...: print ind,ele
...:
0 foo
1 bar
2 foobar
I just discovered heap (in real life and in Python) and now I'm trying to determine if a certain list of random numbers is in heap order.
Problem is I'm not sure myself if I actually understand "heap" in practice even though I believe the definition provided makes sense.
I found some practice problems that should help you write heap psuedo code.
This is the problem and below it is my attempt at solving it:
Write a function that checks whether a list of numbers is a heap or not:
Given a list, it returns True if the numbers are in a heap order, and False if the numbers are not and have the programme return and print the answer.
Example:
returns True:
the following list is in heap order: [0,1, 10, 2, 3, 11, 12, 4, 5, 19, 15]
returns False
the following list is not in heap order: [0, 1, 10, 2, 15, 11, 12, 4, 5, 19, 3]
Then there were 2 lists with a bunch of random numbers from 1 - 100 thrown in there, and some repeat.
def heap_or(A):
n = len(A)
for i in range(n):
start = (len(A) - 2) / 2
while start >= 0:
siftDown(A, start, len(A) - 1)
start -= 1:
return 'True'
else:
return 'False'
def siftDown(A, start, end):
root = start
while root * 2 + 1 <= end:
number = root * 2 + 1
if number + 1 <= end and A[number] < A[number + 1]:
number += 1
if number <= end and A[root] < A[number]:
A[root], A[number] = A[number], A[root]
root = number
else:
return
print
Can somebody please give me a hand? Because I'm not really sure if I'm defining heap correctly the code is giving me a hard time as well!
The heap property (for a max heap) is that each node should be greater than or equal to its parent. The parent of element i in a binary heap stored in an array is element (i - 1) // 2:
def is_heap(A):
return all(A[i] >= A[(i - 1) // 2] for i in range(1, len(A)))
Obviously because the heap is stored in array we don't need to check the shape.