I just started "Algorithmic toolbox" on Coursera, and was writing their version of the Fibonacci program in python 2.7
def fibonacci(n):
F = []
F[0] = 0
F[1] = 1
for i in range(0,n):
F[i] = F[i-1] + F[i-2]
return F[n]
fibonacci(3)
But, I keep getting this error:
Traceback (most recent call last):
File "fibonacci.py", line 11, in <module>
fibonacci(3)
File "fibonacci.py", line 3, in fibonacci
F[0] = 0
IndexError: list assignment index out of range
You can't create new elements in a Python list by assigning to non-existing indices. Your list is empty, so indices 0 and 1 don't exist.
Use list.append() instead:
def fibonacci(n):
F = [0, 1] # a list with two initial elements
for i in range(2, n + 1):
F.append(F[i-1] + F[i-2]) # add new value to the list
return F[n]
Note that the loop starts at 2, not 0, because you already have the values for 0 and 1. The stop argument to range() is not included so if you want to find the nth fibonacci number, you need to run the range up to n + 1.
Now the code works:
>>> def fibonacci(n):
... F = [0, 1]
... for i in range(2, n + 1):
... F.append(F[i-1] + F[i-2])
... return F[n]
...
>>> fibonacci(10)
55
Note that you don't really need to store all values in a list; you only need to track the last 2. You could use just two variables and swap these around for each iteration; one stores the
def fibonacci(n):
prev, curr = 0, 1 # two variables, one set to 0, the other to 1
for _ in range(n - 1): # run n - 2 times
prev, curr = curr, prev + curr
return curr
Note that this doesn't do any boundary tests on n, so for n = 0 the result is going to be incorrect (1 is returned rather than 0). This is easily remedied with a if n < 1: return 0 line at the top.
It's because when the program reaches F[0] it tries to evaluate what's in the 0th index of F. The trouble is that F is initially an empty list and thus has no 0th index. You want to append those elements using F.append(0) and F.append(1), instead.
You have to append values to the list, because its of size 0. Python lists do not autogrow when you add an item at the next index, you have to specify it, for example with the append function
F = []
F.append(0)
F.append(1)
# [0, 1]
# OR
F = [0, 1]
# [0, 1]
There are a couple problems with your code:
def fibonacci(n):
F = [] #3
F[0] = 0
F[1] = 1
for i in range(0,n):
F[i] = F[i-1] + F[i-2] #1
return F[n] #2
First iteration this will be F[0] = F[-1] + F[-2], which is well defined in Python but not what you want. You might want to review Python's indexing scheme.
F[n] refers to the n+1th element, since Python is 0 indexed. Range is [lower, upper), so it doesn't actually have i = n on the final iteration.
As Martijn commented below, the third issue is that you can't simply index into an empty list. You have to either do successive appends, or allocate the entire list as F = [0]*n.
you need to start your loop at 2 not 0.
def fibonacci(n):
F = [0,1]
if n<0:
return None
if n<2:
return F[n]
for i in range(2,n):
F[i] = F[i-1] + F[i-2]
return F[n]
fibonacci(3)
Related
I am trying to get the max pair wise product using python this time around and the concepts of certain aspects are still new to me. I continue to get a list index out of bounds error and stackoverflows of which I do not know how to deal with given the fact that I can not choose types in Python.
I looked into enumerate and other iterate(ble) functions but to no avail. Id answered this could help future people with simple for loop questions in migration from C to python.
def max_pairwise_product(numbers):
n = len(numbers)
max_product = 0
for first in range(n):
for second in range(first + 1, n):
max_product = max(max_product,
numbers[first] * numbers[second])
return max_product
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = 1
for i in range(2,n,1):
if (numbers[i]>numbers[index1]):
index1 = i
if (index1 == 1):
index2 = 2
else:
index2=1
for i in range(1,n):
if(numbers[i]!=numbers[index1] and numbers[i]>numbers[index2]):
index2 = i
return (numbers[index1]*numbers[index2])
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_product_fast(input_numbers))
Traceback (most recent call last):
File "C:/Users/Tevin/.PyCharmCE2018.3/config/scratches/scratch_1.py", line 31, in <module>
print(max_pairwise_product_fast(input_numbers))
File "C:/Users/Tevin/.PyCharmCE2018.3/config/scratches/scratch_1.py", line 27, in max_pairwise_product_fast
return (numbers[index1]*numbers[index2])
IndexError: list index out of range
why dont you find the 2 max numbers in your list and multiply them to get the max product. find the max of list then save it in some variable. remove it from the list and find the max again. then multiply this with your saved variable.
as for your code, what is this line for?
input_n = int(input())
you are not using the input_n variable anywhere.
and the line:
input_numbers = [int(x) for x in input().split()]
your code will ask you for 2 inputs. when you first enter your input, it is saved in the input_n variable. then your second input is saved as input_numbers. something is wrong with the type of input you are giving the program.
If I understand your max_pairwise_product_fast correctly, you are trying to find the largest and second largest number and multiply them. The problem is that you initialize index1 as 1, and index2 with 1 or 2, but array-indexes start with 0. Thus, your code will fail for a list with only two elements, e.g. [1,2]. Change the starting indices to 0, and change the range in the loops accordingly, and it will work.
You can also remove some of the checks, e.g. the if/else, as that's redundant with the check you have in your second loop. Also, by comparing number[index1] and number[index2] you could miss the highest product if the highest number appears twice, e.g. [1,2,2].
Staying close to your original code, you can try this:
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = 0
for i in range(n):
if numbers[i] > numbers[index1]:
index1 = i
index2 = 0
for i in range(n):
if index2 != index1 and numbers[i] > numbers[index2]:
index2 = i
return numbers[index1] * numbers[index2]
But you could also use max instead of those two loops:
def max_pairwise_product_fast(numbers):
n = len(numbers)
index1 = max(range(n), key=lambda i: numbers[i])
index2 = max((i for i in range(n) if i != index1), key=lambda i: numbers[i])
return numbers[index1] * numbers[index2]
Or sort the entire array and pick the highest two:
def max_pairwise_product_fast(numbers):
second, first = sorted(numbers)[-2:]
return first * second
Note, however, that this might still fail if the list includes negative numbers, e.g. [1, 2, -3, -4]. For this, you could call the same function again with all the numbers in the list negated and pick the higher of the two results.
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'm trying to solve the following challenge from codesignal.com:
Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
Example
For a = [2, 1, 3, 5, 3, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than the second occurrence of 2 does, so the answer is 3.
For a = [2, 4, 3, 5, 1], the output should be
firstDuplicate(a) = -1.
The execution time limit is 4 seconds.
The guaranteed constraints were:
1 ≤ a.length ≤ 10^5, and
1 ≤ a[i] ≤ a.length
So my code was:
def firstDuplicate(a):
b = a
if len(list(set(a))) == len(a):
return -1
n = 0
answer = -1
starting_distance = float("inf")
while n!=len(a):
value = a[n]
if a.count(value) > 1:
place_of_first_number = a.index(value)
a[place_of_first_number] = 'string'
place_of_second_number = a.index(value)
if place_of_second_number < starting_distance:
starting_distance = place_of_second_number
answer = value
a=b
n+=1
if n == len(a)-1:
return answer
return answer
Out of the 22 tests the site had, I passed all of them up to #21, because the test list was large and the execution time exceeded 4 seconds. What are some tips for reducing the execution time, while keeping the the code more or less the same?
As #erip has pointed out in the comments, you can iterate through the list, add items to a set, and if the item is already in a set, it is a duplicate that has the lowest index, so you can simply return the item; or return -1 if you get to the end of the loop without finding a duplicate:
def firstDuplicate(a):
seen = set()
for i in a:
if i in seen:
return i
seen.add(i)
return -1
Create a new set and find its already in the new list, if its there return the element:
def firstDuplicate(a):
dup = set()
for i in range(len(a)):
if a[i] in dup:
return a[i]
else:
dup.add(a[i])
return -1
This is just an idea, I didn't verify it but it should work. It seems there's no memory limit but just a time limit. Therefore using space to trade time is probably a practical way to do this. The computation complexity is O(n). This algorithm also depends on the condition that the number range is between 1 to len(a).
def first_duplicate(a):
len_a = len(a)
b = [len_a + 1] * len_a
for i, n in enumerate(a):
n0 = n - 1
if b[n0] == len_a + 1:
b[n0] = len_a
elif b[n0] == len_a:
b[n0] = i
min_i = len_a
min_n = -1
for n0, i in enumerate(b):
if i < min_i:
min_i = i
min_n = n0 + 1
return min_n
Update:
This solution is not as fast as the set() solution by #blhsing. However, it may not be the same if it was implemented in C - it's kinda unfair since set() is a built-in function which was implemented in C as other core functions of CPython.
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
def fact(n):
fac = 1
while (n>1):
fac = fac*n
n -= 1
return fac
z = 0
t = int(raw_input())
nz = []
for i in range(0,t):
c = 0
n = int(raw_input())
z = fact(n)
z = list(str(z))
for j in range(len(z)-1,1,-1):
if z[j] != '0':
break
else:
c +=1
nz[i].append(c)
for k in range(0,t):
print nz[k]
Hello I am getting
Indexerror : index out of range at " nz[i].append(c)
This program should calculate trailing zeros in the factorial of N.
Can you also please help me optimize my code, so it can run also for large values of N?
nz is empty list. It doesn't have any elements, so nz[i] would always raise IndexError. Perhaps you meant nz.append(c) ie. add c at the end of nz.
This is how does append() work:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
so you may want to change nz[i].append(c) to nz.append(c), since your i index is already handled by the append function. You're actually assuming you have an i element in your list, which is false, since you are using an empty list
About optimizing, your problem is probably due to your recursion limit. Try import sys; sys.getrecursionlimit() in your python shell, you should see something like 1000 as result.
Swapping for an iterative version of the factorial function could be a start
def fact(n):
r = 1
for x in range (n):
r = r * (x+1)
return r