I came across an issue swapping values in a list by using the indices as placeholders to keep track of which positive integers appeared.
The question is here (from Leetcode)
Given an unsorted integer array nums, find the smallest missing positive integer.
You must implement an algorithm that runs in O(n) time
and uses constant extra space.
Input: nums = [3,4,-1,1]
Output: 2
Example 3
My initial approach was:
for i in range(len(arr)):
while arr[i] > 0 and len(arr) > arr[i] and i != arr[i]-1 and arr[i] != arr[arr[i]-1]:
print('swapping to index ' + str(i) + ' value ' + str(arr[arr[i] - 1]))
print('swapping to index ' + str(arr[i]-1) + ' value ' + str(arr[i]))
arr[i], arr[arr[i] - 1] = arr[arr[i] - 1], arr[i]
print(arr)
But this outputs:
swapping to index 0 value -1
swapping to index 2 value 3
[-1, 4, 3, 1]
swapping to index 3 value -1
swapping to index 0 value 1
**[-1, 4, 1, -1]** (??)
Whereas if I set a variable j = arr[i] - 1 and run the same code
for i in range(len(arr)):
while arr[i] > 0 and len(arr) > arr[i] and i != arr[i]-1 and arr[i] != arr[arr[i]-1]:
j = arr[i] - 1
print('swapping to index ' + str(i) + ' value ' + str(arr[j]))
print('swapping to index ' + str(j) + ' value ' + str(arr[i]))
arr[i], arr[j] = arr[j], arr[i]
print(arr)
This swaps correctly
swapping to index 0 value -1
swapping to index 2 value 3
[-1, 4, 3, 1]
swapping to index 3 value -1
swapping to index 0 value 1
[1, 4, 3, -1] (as intended)
Could someone explain this to me?
When you swap values
arr[i], arr[arr[i] - 1] = arr[arr[i] - 1], arr[i]
then it runs something like
variable = arr[arr[i] - 1], arr[i]
arr[i], arr[arr[i] - 1] = variable
but in second line it still has to assign values one by one and first it will assign
arr[i] = ...
and later
arr[arr[i] - 1] = ...
but when it assign second value then arr[i] will already have new value instead of old value - and this makes problem.
When you use j = arr[i] - 1 and
arr[j] = ...
then j has all time the old value - ant then it works correctly.
Related
I am trying the 15. 3Sum code challenge on LeetCode:
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
Example 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Here is my attempt:
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) < 3:
return []
nums.sort()
ret_val = []
for i in range(len(nums) - 2):
if i - 1 >= 0 and nums[i - 1] == nums[i]:
while nums[i - 1] == nums[i] and i < len(nums) - 2:
i += 1
if nums[i - 1] == nums[i]:
break
j = i + 1
k = len(nums) - 1
# This is our target sum
target = -nums[i]
while j < k:
if j - 1 != i and nums[j - 1] == nums[j]:
while nums[j - 1] == nums[j] and j < k:
j += 1
elif k + 1 != len(nums) and nums[k + 1] == nums[k]:
while nums[k + 1] == nums[k] and j < k:
k -= 1
else:
if nums[j] + nums[k] == target:
ret_val.append([nums[i], nums[j], nums[k]])
j += 1
k -= 1
elif nums[j] + nums[k] < target:
j += 1
else:
k -= 1
return ret_val
There is apparently a bug in my code that I couldn't figure out, even after running the Python Debugger. My code gives the wrong result when I use the input of [-11, 1, -12, -12, 10]. It creates an unnecessary duplicate in the answer. I've never seen this happen before, but Python seems to run the for loop one too many times.
The expected output should be [[-11, 1, 10]], but it instead gives [[-11, 1, 10], [-11, 1, 10]]. Another interesting thing I discovered is that by removing either one or both instances of -12, it ends up giving the correct answer of [[-11, 1, 10]].
What is the problem in my code?
The reason is that your outer loop will sometimes increment i (the loop variable). This is not good, because that incremented i value is scheduled to be i's value in a next iteration of that loop, and so you will have two iterations happening with the same value for i.
Note how Python's for i in range iteration does not take into account any increment you apply to i in one of the iterations. The full range of values will be iterated, no matter what you do with i in the mean time. This is different from more traditional for loop constructs that you find in other programming languages:
for (int i = 0; i < len(nums) - 2; i++)
...as in that case the loop's i++ will just act on whatever value i has at that moment, taking into account any change you made to i during an iteration. Again, this is not how it works with an iterator such as Python's range function returns.
The solution is to just exit the current iteration when you would have wanted to increment i, since you know that the next iteration will have that incremented value for i anyhow.
So change this piece of code:
if i - 1 >= 0 and nums[i - 1] == nums[i]:
while nums[i - 1] == nums[i] and i < len(nums) - 2:
i += 1
if nums[i - 1] == nums[i]:
break
to this:
if i - 1 >= 0 and nums[i - 1] == nums[i]:
continue
That will solve the issue.
I am trying to set up cyclic sort, where the range of numbers are known ahead of time
def cyclic_sort(nums):
# TODO: Write your code here
i = 0
while i < len(nums):
while nums[i] - 1 != i:
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
i += 1
return nums
print(cyclic_sort([2, 1, 3]))
However the code just hangs however when I refactor to the below the code runs
def cyclic_sort(nums):
# TODO: Write your code here
i = 0
while i < len(nums):
while nums[i] - 1 != i:
other = nums[i] - 1
nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]
i += 1
return nums
print(cyclic_sort([2, 1, 3]))
Can someone help me understand what is happening?
nums[i] gets reassigned first, so when nums[nums[i] - 1] = ... is evaluated, it is taking the new value of nums[i], which in this case is 1.
So you get nums[0] = 1, and then nums[1-1] = 2, in your example.
You are setting the value of the current element to the new value you want to swap with, and then setting the element at the position of the value of the swapped element to the current value.
Your code is equivalent to:
x, y = nums[nums[i] - 1], nums[i]
nums[i] = x #nums[i] is set to value of element you want to swap
nums[nums[i] - 1] = y #nums[(value at swapped element) - 1] = (current elements original value)
You also don't need the while loop, which doesn't do anything useful, because you already know which position the number should be in based on the value, so you only need to check it once per position.
Swap order of assignments, since nums[i] doesn't get affected by changing the value of nums[nums[i] - 1].
def cyclic_sort(nums):
# TODO: Write your code here
i = 0
while i < len(nums):
if nums[i] - 1 != i:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
i += 1
return nums
print(cyclic_sort([2, 1, 3]))
This question already has an answer here:
Find Minimum Number of Swaps to Sort an Array [duplicate]
(1 answer)
Closed 3 years ago.
I am trying to sort list in decreasing order and get the number of swaps required to sort the list in decreasing order [3, 1, 2] → [3, 2, 1]. i.e from the highest element of the list to the lowest using python. The function i have is sorting the list in increasing order i.e [3, 1, 2] → [1, 2, 3] . How would i sort it in decreasing order and get the number of swaps it took to sort the list?
def count_inversions(ratings):
swap = 0;
for i in range(len(ratings)):
if(i + 1 != ratings[i]):
t = i
while(ratings[t] != i+1):
t++
temp = ratings[t]
ratings[t] = ratings[i]
ratings[i] = temp
swap = swap + 1
return swap
I wrote a bubble sorting code some time ago, it might help you
def bubble_sort(arr, reversed=False):
swap_cnt = 0
i = len(arr) - 1
while i > 0:
for j in range(i):
if not reversed:
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
swap_cnt += 1
if reversed:
if arr[j] < arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
swap_cnt += 1
i -= 1
print('Number of swaps: {}'.format(swap_cnt))
return arr
if __name__ == "__main__":
print(bubble_sort([2, 4, 8, 5, 1, 9, 4]))
print(bubble_sort([2, 4, 8, 5, 1, 9, 4], reversed=True))
I followed the clrs book for algo.
I'm trying make heapsort in python. But It give me the error that r falls out side of the index but I don't know why.
def Max_Heapify(A,i,size_of_array):
l = 2*i
r = l + 1
if l <= size_of_array and A[l] > A[i]:
largest = l
else:
largest = i
if r <= size_of_array and A[r] > A[largest]:
largest = r
if i != largest:
A[i], A[largest] = A[largest], A[i]
Max_Heapify(A,largest,size_of_array)
def Build_Max_Heap(A,size_of_array):
for i in range((math.floor(size_of_array/2)) - 1 , 0 ,-1):
Max_Heapify(A,i,size_of_array)
def Heapsort(A,size_of_array):
Build_Max_Heap(A,size_of_array)
for i in range(size_of_array - 1 ,0 ,-1):
A[0],A[i] = A[i],A[0]
size_of_array = size_of_array - 1
Max_Heapify(A,0,size_of_array)
In most of the programming languages, the size of the array is bigger than the last index. For example, the following array: A = [1, 2, 3], its size is 3, but the index of the last element is 2 (A[3] should return that it is out of index). You are verifying if r is less or equal to the array size, so when it is equal, it is bigger than the last index. Your verification should be:
if r < size_of_array
The question is classical 0-1 knapsack problem:
Given n items with size A[i], an integer m denotes the size of a backpack. How full you can fill this backpack?
Example
If we have 4 items with size [2, 3, 5, 7], the backpack size is 11, we can select 2, 3 and 5, so that the max size we can fill this backpack is 10. If the backpack size is 12. we can select [2, 3, 7] so that we can fulfill the backpack.
I wrote two solution for it, and the first recursion one works, but DP one doesn't.
class Solution:
# #param m: An integer m denotes the size of a backpack
# #param A: Given n items with size A[i]
# #return: The maximum size
def backPack(self, m, A):
if len(A) <= 0 or m <= 0:
return 0
if A[0] > m:
return self.backPack(m, A[1:])
put = A[0] + self.backPack(m - A[0], A[1:])
not_put = self.backPack(m, A[1:])
return max(put, not_put)
def YetAnotherBackPack(self, m, A):
mapping = [(m + 1) * [0]] * (len(A) + 1)
for i in range(len(A) + 1):
for j in range(m + 1):
if i == 0 or j == 0:
mapping[i][j] = 0
elif A[i - 1] > j:
mapping[i][j] = mapping[i - 1][j]
else:
put = mapping[i - 1][j - A[i - 1]] + A[i - 1]
mapping[i][j] = max(mapping[i - 1][j], put)
return mapping[len(A)][m]
print Solution().backPack(10, [3, 4, 8, 5]) # output: 9
print Solution().YetAnotherBackPack(10, [3, 4, 8, 5]) # output: 10 WRONG!
Can anyone help point that what's wrong with my DP solution?
This line is the problem:
mapping = [(m + 1) * [0]] * (len(A) + 1)
You're creating a list of lists, but you're not creating a unique inner list for each row - all of the rows are pointing to the same list (the one created by [(m + 1) * [0]].
To fix it, change that line to something like this:
mapping = [[0 for i in range(m+1)] for j in range(len(A) + 1)]
For a more detailed description of this issue: Nested List Indices