I've completed a question from algo expert that asks you to loop through an array of numbers to find the two numbers that add to a target sum. I'm trying to understand why this function does not work without the iterators being aliased.
input: [3, 5, -4, 8, 11, 1, -1, 6], 10
output: [-1, 11]
This is the correct solution:
def twoNumberSum(array, targetSum):
for i in range(len(array) - 1):
firstNum = array[i]
for j in range(i + 1, len(array)):
secondNum = array[j]
if firstNum + secondNum == targetSum:
return [firstNum, secondNum]
return []
and I don't understand why this does not work:
def twoNumberSum(array, targetSum):
for i in range(len(array) - 1):
for j in range(i + 1, len(array)):
if i + j == targetSum:
return [i, j]
return []
As mentioned in the comments, i and j are no values but your index.
It is always good to just test the output with a small example.
when
a=[6,7,8,9,10]
try to see what the range is over the length of a
for i in range(len(a)):
print(i)
this will result in
0
1
2
3
4
and not
6
7
8
9
10
I hope that made it clearer.
Keep healthy.
Related
Here is my question I would like to not use numbers that I use but rather that I can put in random numbers ranging from 0 to 50 and then the list can use bubble method to sort it but I can understand how I can use the randomly generated numbers in here
def bubbleSort(array):
for i in range(len(array)):
data = [8, 45, 0, 11, 6]
swapped = False
for j in range(0, len(array) - i - 1):
if array[j] > array[j + 1]:
# swapping occurs if elements
# are not in the intended order
temp = array[j]
array[j] = array[j+1]
array[j+1] = temp
swapped = True
if not swapped:
break
You must call your function with the list you want to sort, i.e. with the function:
def bubble_sort(lst):
n = len(lst)
for i in range(n - 1):
swapped = False
for j in range(0, n - i - 1):
if lst[j] > lst[j + 1]:
swapped = True
lst[j], lst[j+1] = lst[j+1], lst[j]
if not swapped:
return
You'll call it like this:
data = [8, 45, 0, 11, 6]
bubble_sort(data)
print(data) # should now be sorted
(bubble sort, sorts the list in-place)
my method for sorting an array written in python:
array = [3, 2, 1]
for i in range(len(array)):
minVal = array[i]
for j in range(i + 1, len(array)):
if (array[j] < array[i]):
if (array[j] <= minVal):
minVal = array[j]
if i < len(array) - 1:
array[i + 1] = array[i]
array[i] = minVal
print(array)
how do i think it works?
the first cycle will be executed 3 times
first iteration:
#i will check number 3 with numbers 2 and 1
#expected output:
minVal = 1
array = [1, 3, 2]
second iteration:
#i will check number 3 with number 2
#expected output:
minVal = 2
array = [1, 2, 3]
last iteration:
#I do not know if he is needed.
#perhaps it is worth writing `range(len(array) - 1)` in the first loop?
#and because of this iteration, I also added the check `if i <len (array) - 1:`
expected output at the end: [1, 2, 3]
what i got: [1, 1, 3]
Think about your logic: You find the minimum value and then replace the i item with it but only advance the i item one index ahead to i+1. By doing so, after the first iteration you have the list as [1, 3, 1]. Let's break it down:
you start with [3, 2, 1]
minVal = array[i] = 3
After the j loop we find that minVal = 1
Now we do array[i + 1] = array[i] -> array[1] = 3. So now we have [3, 3, 1].
Now we do array[i] = minVal -> array[0] = 1. So now we have [1, 3, 1].
The element 2 has disappeared from the list!
To fix this, you need to save the minVal's index and replace the two items, not override another item:
array = [3, 2, 1]
for i in range(len(array)):
minIndex = i
for j in range(i + 1, len(array)):
if (array[j] < array[i]):
if (array[j] <= array[minIndex]):
minIndex = j
minVal = array[minIndex]
if i < len(array) - 1:
array[minIndex] = array[i]
array[i] = minVal
print(array)
Now there are some points to simplify and improve your code:
There is no need to check that array[j] < array[i] on every iteration - in the first iteration it is equal to minVal/array[minIndex] anyway, so you can remove one if.
There is no need for the last if - instead of checking every iteration if we got to the last element, just remove it from the loop - for i in range(len(array)-1).
The replacement can be done in one line without the need to even save minVal - see this SO question.
So the improved version according to the above can be:
array = [3, 2, 1]
for i in range(len(array)-1):
minIndex = i
for j in range(i + 1, len(array)):
if array[j] < array[minIndex]:
minIndex = j
array[minIndex], array[i] = array[i], array[minIndex]
print(array)
You are currently searching an array for the minimum value including and past the current index. This is an O(N^2) approach, and quite robust. However, you need to implement it correctly.
The check
if (array[j] < array[i]):
if (array[j] <= minVal):
is redundant. You shouldn't restrict your test by the original minimum value, although it does no harm, since minVal <= array[i] in all cases.
You don't really care about the value of minVal as much as you do about its location. You more-or-less correctly identify minVal as array[j], but then you swap it out as array[i + 1] = array[i]. Where is the correct j recorded?
Here is the same idea, but without the extra check, and using minJ to illustrate the caching of j vs the value:
array = [3, 2, 1]
for i in range(len(array) - 1): # Don't bother iterating the last element
min_j = i # Only record indices
for j in range(i + 1, len(array)):
if array[j] < array[min_j]: # Only test current minimum
min_j = j
array[i], array[min_j] = array[min_j], array[i]
print(array)
Couple of small tweaks:
You don't need to iterate over the last element, so shorten the outer range by one.
The idiomatic way to swap two quantities in python is x, y = y, x. If you're going to use a temporary variable anyway, it may as well be a tuple that enhances legibility.
I'm trying to make a IDDFS algorithm for a n-puzzle problem. However, the move function doesn't work properly. It will output the next move but change the values of the previous one (argument). Any advice on how to prevent this from happening would be greatly appreciated :)
def move_blank(i, j, n):
if i + 1 < n:
yield i + 1, j
elif i - 1 >= 0:
yield i - 1, j
elif j + 1 < n:
yield i, j + 1
elif j - 1 >= 0:
yield i, j - 1
def move(state):
[i, j, grid] = state
n = len(grid)
for pos in move_blank(i, j, n):
i1, j1 = pos
grid[i][j], grid[i1][j1] = grid[i1][j1], grid[i][j]
yield [i1, j1, grid]
grid[i][j], grid[i1][j1] = grid[i1][j1], grid[i][j]
def is_goal(state, goal):
return state == goal
def dfs_rec(puz, goal):
if is_goal(puz[-1], goal):
return puz
else:
for next_state in move(puz[-1]):
if next_state not in puz:
next_path = puz + [next_state]
solution = dfs_rec(next_path, goal)
if solution != None:
return solution
return None
goal = [0, 2, [[3, 2, 0], [6, 1, 8], [4, 7, 5]]]
test = [0, 0, [[0, 7, 1], [4, 3, 2], [8, 6, 5]]]
path = dfs_rec([test], goal)
The problem is in move_blank. The generated moves are not mutually exclusive, yet only one of them will be generated. Replace all elifs with a simple if:
def move_blank(i, j, n):
if i + 1 < n:
yield i + 1, j
if i - 1 >= 0:
yield i - 1, j
if j + 1 < n:
yield i, j + 1
if j - 1 >= 0:
yield i, j - 1
There are other, less critical, issues with implementation:
if next_state not in puz is awfully expensive. Enumerating states and storing their id in a set would be much better (there are 362k states for an 8-puzzle, list lookup is faster than set only up to ~30 elements)
reliance on mutable arguments isn't a good practice. No immediate issues here but it might bite when you don't expect.
Storing state as a 9-tuple would fix this and the previous concern.
solution = dfs_rec(next_path, goal) This problem is solvable and would be much cheaper without recursion. Yes, wikipedia pseudocode is not optimal.
it is not IDDFS - there is no depth limit per iteration
I´m working on a simple bubble sort script. I've tried several test cases, but some of them doesn't order the numbers as expected. Here is my code with one test case that does not work.
def bubble_sort(array):
i = 0
j = 1
for x in range(0, len(array)):
for y in range(1000):
if(i == 4 and j == 5):
i, j = 0, 1
if(array[i] <= array[j]):
pass
if(array[i] > array[j]):
array[i], array[j] = array[j], array[i]
#print(array)
i, j = i + 1, j + 1
pass
pass
return(array)
I´m passing this list to the code
[7, 3, 1, 2, 3, 3, 10, 15, 2]
And the output is
[1, 2, 3, 3, 7, 3, 10, 15, 2]
I can´t find the mistake on the code, although I think is in the number and logic of the iterations.
Hope someone can help me.
This is just a fixed up version of your code:
I don't understand why your loops use x and y as enumeration values in the for-loops, but then you use another pair of indices: i and j. The i and j don't seem needed.
if(i == 4 and j == 5) - not needed. Is this just a debugging thing?
pass is just a no-op. I don't think you need it.
It's spelled bubble, not buble
It gets simple pretty fast:
def bubble_sort(array):
for x in range(0, len(array)):
for y in range(x+1, len(array)):
if(array[x] > array[y]):
array[x], array[y] = array[y], array[x]
return(array)
Here is different version of your code.
def bubbleSort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
After this codes, you need to initialize(create) your array, then call your def like this; bubbleSort(arr) after all this things you can print your array in for loop.
for i in range(len(arr)):
print(arr[i])
I tried implementing Insertion sort with for loops only and wrote the following code:
def isort(L): #implementation with a for loop
for i in range(1,len(L)):
small = L[i]
M = range(i)
M.reverse()
for j in M:
if small<L[j]:
L[j+1]=L[j]
else:
break
L[j+1] = small
return L
L = [5,4,3,2,1]
M = isort(L)
print M
This gives the output [5,1,2,3,4]. Can someone please point out where I am making a mistake
Change (the fix shown in the question is easy, the one-off error was caused by one little +1 :)):
L[j+1] = small
To:
L[j] = small
Testing:
>>> isort([5, 4, 3, 2, 1])
[1, 2, 3, 4, 5]
However, there are some other things with your code, as illustrated- it will not work alot of the time. With a fair few tweaks, we can get it to work:
def isort(L):
for i in range(1,len(L)):
small = L[i]
M = range(-1, i)
M.reverse()
for j in M:
if j>=0 and small<L[j]:
L[j+1]=L[j]
else:
break
L[j+1] = small
return L
Testing:
>>> isort([4, 5, 3, 2, 1])
[1, 2, 3, 4, 5]
The post condition for the inner loop is that j is pointing for the first value that is smaller than small (this is achieved by the break call). However, the loop naturally exists when j=0, therefore in every last inner iteration, the condition is not what you'd expect.
To fix it, I suggest initializing M from -1:
M = range(-1, i)
But then, you have to check as well that j is positive (to avoid making changes you don't want to):
if j>=0 and small<L[j]:
L[j+1]=L[j]
This is little tricky :
I took the inner loop range function as range(j, -2, -1) , so the inner loop always breaks at one position ahead, so the last statement arr[j + 1] = key works perfectly
arr = [5, 4, 3, 2, 1]
for i in range(1, len(arr)):
j = i - 1
key = arr[i]
for j in range(j, -2, -1):
if j < 0 or key >= arr[j]:
break
else:
arr[j + 1] = arr[j]
arr[j + 1] = key
if __name__ == "__main__":
n = int(input("How many numbers ?\t"))
nums = [int(x) for x in input("Enter {} numbers\t".format(n)).split()]
for i in range(1,n):
val = nums[i]
for j in range(i-1,-2,-1):
if j < 0 : break
if nums[j] > val:
nums[j+1] = nums[j]
else:
break
nums[j+1] = val
for num in nums:
print(num,end=' ')
print()