Index out of range | Python - python

I am attempting the TwoSum Question using python and have tried the two pointer method essentially having a pointer at the beginning and end of the array, when the sum of the two indexes is greater than the value where are looking for it decrements the ending pointer one index less and if the sum is less than it increments the beginning pointer by 1. I keep getting an index out of range error and would like to know why it happens. I stepped through my code and everything seems to make sense and my test case passes but it gives me an out of range error when I get a list like this:
[-1,-2,-3,-4,-5] and the target being -8
the goal is to output index positions [2,4] using the two pointer technique
Here is my code:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
stack = list()
n = len(nums)
j = (len(nums)-1)
i = 0
while i < n:
tempSum = nums[i] + nums[j]
if tempSum == target:
stack.append(i)
stack.append(j)
break
if tempSum > target:
j-=1
else:
i+=1
return stack

The error happens due to the logic you have built in your while loop. Whenever tempSum is larger than target, you subtract 1 from j. When working with negative numbers, this means that your loop will continue reducing j until it reaches j=-6, at which point it will produce an out of range error.
Try taking the absolute value of tempSum and target within your if statement, then the evaluation will work in case of negative numbers as well.
if abs(tempSum) > abs(target):
j-=1
else:
i+=1

Related

Python code throws error list out of range, even though the logic is same

1)
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i = 1
while i < len(nums)-1:
if nums[i]==nums[i-1] and nums[i]==nums[i+1]:
del nums[i]
else:
i+=1
return len(nums)
The code above happens to work perfectly.
2)
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n = len(nums)-1
i = 1
while i < n:
if nums[i]==nums[i-1] and nums[i]==nums[i+1]:
del nums[i]
else:
i+=1
return len(nums)
But the 2nd code throws this error :-
IndexError: list index out of range
if nums[i]==nums[i-1] and nums[i]==nums[i+1]:
The logic behind both the codes happens to be same, in the first code we don't store the length of the list nums, instead we use it in while loop directly like while < len(nums) - 1
In the second code, we store the value of len(nums) in a variable n, and use it in a similar fashion in the while loop, while i < n - 1
I don't understand what's the difference between the two.
Your two snippets are not identical.
Notice that the list is modified inside the loop with del nums[i], so its length changes.
In the first code, you access len(nums) every time you need it, so you always get the correct value of len(nums).
In the second code, when you do n = len(nums) - 1, the value of len(nums) - 1 at that time is assigned to the variable n. This variable isn't automatically updated when the value of len(nums) changes, so even after you delete elements of the list, n still has its original value.

Is this code efficient? #LeetCode #two_sum

This is two sum problem from leetcode, I tried to solve, It got accepted. I am asking if this code is efficient enough in terms of memory and space complexity.
My code :
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
l = len(nums)
ans = []
for i in range(l):
compliment = target - nums[i];
# print(a.index(x))
if compliment in nums:
if nums.index(compliment)!=i:
# print(a.index(x))
ans.append(i)
ans.append(nums.index(compliment))
break;
return ans
Your code searches for compliment in nums, and then follows it up with an index function. Later on, you use this index again in nums.index(compliment). Essentially, you're searching through the array three times. A better way would be to search through the array and store the index if found, else -1. If the index is not -1, i.e., present in the array, you can append it to ans. This essentially skips the two lines (and that index function) and traverses the array once instead of thrice.
index_if_found = -1
for index in range(len(arr)):
if arr[index] == search_value:
index_if_found = index
break
You can now use this index index_if_found instead of using the index function.
EDIT: Thanks to Kelly for correcting me on the search algorithm.
Additionally, you have two append methods to the same array. A slightly faster approach would be to use the extend method and add them in the same operation. So instead of
ans.append(i)
ans.append(nums.index(compliment))
You'd have
ans.extend((i, nums.index(compliment)))

Leetcode #35 Search Insert Position (list index out of range)

test=[]
for i in range(len(nums)):
if nums[i+1] > target > nums[i]:
test.append(nums[i])
test.append(target)
else:
test.append(nums[i])
return test.index(target)
I try to create new array sort the value first, then find the index of the target.
It get error in index out of range in line nums[i+1].
How can I correct the code without the big change
Question link: https://leetcode.com/problems/search-insert-position/
What you are doing wrong:
This is because you are using nums[i+1] and since i is in the range 0 to len(nums) it gives index out of range for the last value of i.
You are checking if an element in nums is greater than the previous element or not. This will always be true because nums is sorted. I also don't know why are you appending the nums[i+1] and target to the test list. There's no need to create a new list.
What the question asks you to do
It tells you that the nums is sorted and you need to return the index if target is in nums. If not then return the index where it should be inserted. NOTE: It doesn't ask you to insert the target.
So, the steps which you can follow are:
Loop through nums. You can use for i, num in enumerate(len(nums)):. This will give you the index i.e. i and the value of each element in nums i.e. num.
Take each element to check if the target is greater than or equal to nums[i].
If it is then you need to return that index because that would be the index where the target needs to be inserted. Eg: [1,3,6,8] if target is 5 then it should be inserted at 2 which is the index of nums[i] > target.
If target is greater than the last element of nums then return the last index of nums i.e. len(nums).
Combining all steps. The code we get(Do try it yourself first! Spoiler Alert!):
def searchInsert(self, nums: List[int], target: int) -> int:
for i, num in enumerate(nums):
if num >= target:
return i
return len(nums)

Python Code Optimization Problem (Lintcode Problem 1886 Moving Targets)

I have been working on a problem on https://www.lintcode.com/ and I have ran into a problem while doing one of the questions. The problem requires me to write a function with two parameters. A list of nums and a target num. You have to take all instances of the target from the list and move them to the front of the original list and the function cannot have a return value. The length of the list is between 1 and 1000000. You also have to do it within a time limit, which is around 400 milliseconds. I can solve the problem, I can't pass the last test case where the length of the list is 1000000. Does anyone know how I can make my code faster?
Original Problem Description for anyone who still isn't clear:
Current Code:
def MoveTarget(nums, target):
if len(set(nums)) == 1:
return nums
index = [i for i in range(len(nums)) if nums[i] == target]
for i in index:
nums.insert(0, nums.pop(i))
It works if you do:
def MoveTarget(nums, target):
count = 0
left, right = len(nums) - 1, len(nums) - 1
while left >= 0:
if nums[left] != target:
nums[right] = nums[left]
right -= 1
else:
count += 1
left -= 1
for i in range(count):
nums[i] = target
but I was wondering if there was another, less complicated way.
Here is a simple and relatively efficient implementation:
def MoveTarget(nums, target):
n = nums.count(target)
nums[:] = [target] * n + [e for e in nums if e != target]
It creates a new list with the n target values in the front and append all the other values that are not target. The input list nums is mutated thanks to the expression nums[:] = ....
The solution run in linear time as opposed to the previously proposed implementations (running in quadratic time). Indeed, insert runs in linear time in CPython.
Your code uses 2 loops. One in:
index = [i for i in range(len(nums)) if nums[i] == target]
And one in:
for i in index:
nums.insert(0, nums.pop(i))
Instead, you can combine finding the target and moving it to the front of array with only one loop, which will greatly reduce the execution time:
def MoveTarget(nums, target):
if len(set(nums)) == 1:
return nums
for num in nums:
if num == target:
nums.insert(0, nums.pop(num))

Find the Duplicate Number

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
My solution:
def findDuplicate(nums):
slow = fast = finder = 0
while fast is not None:
slow = nums[slow]
fast = nums[nums[fast]]
if fast is slow:
return slow
return False
nums = [1,2,2,3,4]
print findDuplicate(nums)
My above solution works and gives me o/p 2 but it doesn't work for every input for example it doesn't work for [11,15,17,17,14] or [3,1,2,6,2,3] and gives me error IndexError: list index out of range. I am not able to find patterns and am not able to track down the exact problem. Also tried to change my while condition:
while fast is not None and nums[nums[fast]] is not None:
your help will be greatly appreciated! Thank you.
Since the numbers are between 1 and n and you have been told there is only one duplicate, you can use difference between the sum of the numbers in the array and the sum of numbers from 1 to n to get the duplicate.
def findDuplicate(l):
n = len(l) - 1 # Get n as length of list - 1
return sum(l) - (n * (n + 1) / 2) # n*(n+1)/2 is the sum of integers from 1 to n
So the duplicate is the sum of the list - n*(n+1)/2
Of course, this doesn't generalize to finding duplicates for any list. For that case, you need to use #Jalepeno112 's answer.
The fact that the first one works is a fluke. Let's look at what it does on the first pass.
nums = [1,2,2,3,4]
# slow starts as index 0. So now, you've reassigned slow to be nums[0] which is 1.
# so slow equals 1
slow = nums[slow]
# now you are saying that fast equals nums[nums[0]].
# nums[0] is 1. nums[1] is 2
# so fast = 2
fast = nums[nums[fast]]
On the next pass, slow will be nums[1] which is 2. fast will be nums[nums[2]] which is nums[2] which is 2. At this point slow and fast are equal.
In your second example, you are getting an IndexError because of fast = nums[nums[fast]] If the value at nums[fast] is not a valid index, then this code will fail. Specifically in the second example, nums[0] is 11. nums doesn't have an element at index 11, so you get an error.
What you really want to be doing is performing a nested for loop on the array:
# range(0,len(nums)-1) will give a list of numbers from [0, to the length of nums-1)
# range(1, len(nums)) does the same,
# except it will start at 1 more than i is currently at (the next element in the array).
# So it's range is recomputed on each outer loop to be [i+1, length of nums)
for i in range(0,len(nums)-1):
for j in range(i+1,len(nums)):
# if we find a matching element, return it
if nums[i] == nums[j]:
return nums[i]
# if we don't find anything return False
return False
There are likely other more Pythonic ways to achieve this, but that wasn't your original question.
first you must ensure all numbers in list satisfy your constrains.
to find duplicated numbers in a list Use Counter in collections it will return each number and number of occurrence example :
>>> from collections import Counter
>>> l=Counter([11,15,17,17,14])
>>> l
Counter({17: 2, 11: 1, 14: 1, 15: 1})
to get the most common one use :
>>> l.most_common(n=1)
[(17, 2)]
where n is the number most common numbers you want to get
def duplicates(num_list):
if type(num_list) is not list:
print('No list provided')
return
if len(num_list) is 0 or len(num_list) is 1:
print('No duplicates')
return
for index,numA in enumerate(num_list):
num_len = len(num_list)
for indexB in range(index+1, num_len):
if numA == num_list[indexB]:
print('Duplicate Number:'+str(numA))
return
duplicates([11,15,17,17,14])
duplicates([3,1,2,6,2,3])
duplicates([])
duplicates([5])
l=[]
n= int(input("the number of digit is :"))
l=[0 for k in range(n)]
for j in range(0,n):
l[j]=int(input("the component is"))
print(l)
b=0; c=0
for i in range(n):
if l[i]== l[n-1-i]:
b=1;c=i
if b==1:
print("duplicate found! it is",l[c])
elif b==0:
print("no duplicate")
The answer is unfinished. It tries to convert the array to a linked list. So far it found where the slow pointer and fast pointer met, but this is the halfway solution. To get the solution, we need to initialize another pointer from the beginning of the linked list and walk towards each other. When they meet, that point is the where cycle is detected, in our question it is where the single point is:
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow,fast=0,0
while True:
slow=nums[slow]
fast=nums[nums[fast]]
if slow==fast:
break
slow2=0
while True:
slow2=nums[slow2]
slow=nums[slow]
if slow==slow2:
return slow2

Categories