Partition Array - python

Given an array nums of integers and an int k, partition the array (i.e move the elements in nums) such that: All elements < k are moved to the left. All elements >= k are moved to the right
Return the partitioning index, i.e the first index i nums[i] >= k.
class Solution:
def partitionArray(self, nums, k):
# write your code here
if nums == []:
return 0
left = 0
i = 0
while i <= len(nums):
if nums[i] < k:
i += 1
left += 1
else:
r = nums[i]
del nums[i]
nums.append(r)
i += 1
return left
My idea is to going through the list one by one. The num[i] whose larger than k will be removed and append at the end of the num, the one whose smaller than k will be kept at the original place. Once the whole list has been going through, all the smaller num are at the front. left is a counter at this point for return. But I cannot fix the problem with nums[i]. After the each mods to the list, the counter i cannot point at the correct item in the list.
How can I write the code base on this idea???

You're looking for the index(k). This seems like a homework assignment so you may be limited to what built in functionality you can use. However, a pythonic approach to this is
def solution(nums, k):
return sorted(nums).index(k)
You are doing several things I would recommend avoiding.
Concurrent modification; you should not add or delete from a list while looping it.
You can not loop up to i == len(nums) because list indexes start at 0.
Since you are really just looking for index(k) you need only keep track of numbers less than k and not concern yourself with re-organizing the list.
class Solution:
def partitionArray(self,nums, k):
# write your code here
if nums == []:
return 0
left = 0
i = 0
while i < len(nums):
if nums[i] < k:
left += 1
i += 1
return left

Related

Don't know why the loop doesn't work (Python)

I just recently started learning Python. Tried to solve a problem where you are given an array of integers and you need to find three of them with the sum closest to target.
My idea was to sort the array and then create two pointers - one at the start of the array, moving right, and one at the end of the array, moving left. And the third pointer is supposed to move along the entire array, while the program calculates and uses the sum of all three of them. But it doesn't work. It ignores some of the indexes.
I feel like if I don't understand this I'll never understand loops in general.
nums = [0,1,1,1]
target = 100
nums.sort()
pointer_one = 0
pointer_two = len(nums) - 1
result = nums[0] + nums[1] + nums[2]
while pointer_one < pointer_two:
for i in nums:
if i == pointer_one or i == pointer_two:
pass
else:
sum_num = nums[i] + nums[pointer_one] + nums[pointer_two]
how_close = abs(target - sum_num)
if how_close < abs(target - result):
result = sum_num
pointer_one = pointer_one + 1
pointer_two = pointer_two - 1
print("Result: ", result)`
When you begin my advice is to use the print() to better understand your code:
iterate over items:
for i in nums:
print(i)
0 1 1 1
iterate over indexes:
for i in range(len(nums)):
print(i)
0 1 2 3
Regards
Your for loop iterates over the items of the list, but you use it as an index not the actual value.
The standard for loop with an index would in your case look as:
for i in range(len(nums)):
#rest of your code
Look at the docs for examples of both forms of for loops:
https://docs.python.org/3/tutorial/controlflow.html#for-statements

Jump game 2 leetcode: while loop not terminating

You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0].
Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at nums[i], you can jump to any nums[i + j] where:
0 <= j <= nums[i] and
i + j < n
Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach nums[n - 1].
Example 1:
Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [2,3,0,1,4]
Output: 2
My solution:
class Solution:
def jump(self, nums: List[int]) -> int:
j = len(nums)-1
res = []
while j >= 0:
cursor = j
valid_j = j # this variable will hold the best value of j to be set
while cursor >= 0:
if nums[cursor] + cursor >= j:
valid_j = cursor
cursor-=1
res.append(valid_j)
j = valid_j
return len(res)
Either of the while loop doesn't terminate and I am unable to figure out why. Time limit exceeded error.
Please help by explaining the error.
Thanks!
Your while condition is wrong. It will always be true since j is never going to become negative.
The meaning of j in your algorithm is the index that must be jumped to from some earlier index. But index 0 must never be jumped to, since we already achieved that index by starting there.
To fix this, the while condition should be changed to j > 0.
It should be noted that this is not a very efficient solution, as cursor is repeatedly reading the same values of the list, giving this algorithm a worst time complexity of O(𝑛²).
It is possible to solve this problem without nested loop, using a forward loop.

Reversing the order of a list without using inbuilt functions in Python

I am new to python and in trying to get better I purchased some textbooks. One problem I found in a textbook has me really confused as I feel the solution is obvious. I am given a insertion sort code that orders a list in ascending order. The problem asks to reverse the order of the list (so it is descending) without using in built functions and instead altering the code. Here is the code:
sequence = [5,-2,0,6,10,-5,1]
def myInsertionSort(sequence):
for i in range (1, len(sequence)):
item = sequence[i]
j = i
while j > 0 and sequence[j-1] > item:
sequence[j] = sequence[j-1]
j -= 1
sequence[j] = item
return sequence
myInsertionSort(sequence)
I added an example sequence and the output here is that it orders the sequence in ascending order. I realised the key here was to understand the code, so I used pythontutor.com to visualise and understand each step, and even though I now feel I understand it every edit I make to the code results in an error or un-ordered list.
Consider this slight generalization of your code; I've just refactored the comparison of sequence[j-1] and item to a separate function.
def out_of_order(a, b):
return a > b
def myInsertionSort(sequence):
for i in range (1, len(sequence)):
item = sequence[i]
j = i
while j > 0 and out_of_order(sequence[j-1], item):
sequence[j] = sequence[j-1]
j -= 1
sequence[j] = item
return sequence
The while loop swaps two items if they are considered out of order. Now think about what happens if you change what it means for two items to be out of order by modifying the definition of out_of_order.
Your book example is not very pythonic.
This is called insertion sort. It may help to see how it works with an animation. Take a look at this website (make sure to select insertion [INS] sort): https://visualgo.net/bn/sorting
That be said keep a close eye on the > in the while loop statement sequence[j-1] > item. That is my hint.
sequence = [5,-2,0,6,10,-5,1]
def myInsertionSort(sequence):
for i in range (1, len(sequence)):
item = sequence[i]
j = i
while j > 0 and sequence[j-1] < item:
sequence[j] = sequence[j-1]
j -= 1
sequence[j] = item
return sequence
myInsertionSort(sequence)
If it makes it easier to read, here is there example written a little differently:
sequence = [5,-2,0,6,10,-5,1]
def myInsertionSort(sequence):
for j in range (1, len(sequence)):
while j > 0 and sequence[j-1] > sequence[j]:
sequence[j], sequence[j-1] = sequence[j-1], sequence[j] # Flip the elements
j -= 1 # Move down one index
return sequence
print(myInsertionSort(sequence))
A super easy way is simply to return sequence[::-1] and it will give you an ascending ordered list. I don't consider list reverse technique as in-built-function.
return sequence[::-1]
But if you think that it counts, here is the alternative code:
sequence = [5,-2,0,6,10,-5,1]
def myInsertionSort(sequence):
for i in range (1, len(sequence)):
item = sequence[i] # for example, when i is 0, item = 5
j = i # now j = i = 1
while j > 0 and sequence[j-1] < item:
# our goal is to push smaller numbers towards the end of the list
# e.g. when i = 1, j = 1 sequence[j-1] = sequence[0] = 5, so sequence[0] > sequence[1], we want to keep their position, now move on
#. when i = 1, j = 2, sequence[j-1] = sequence[1] = -2, so sequence[1] < sequence[2], we must switch them
sequence[j] = sequence[j-1] # sequence[1] is reassigned the current value of sequence[2] because the latter is bigger
j -= 1 # now we also must put the smaller value in the current sequence[2] position
sequence[j] = item # sequence[2] = item (item is the sequence[1])
return sequence
myInsertionSort(sequence)

Minimum count to sort an array in Python by sending the element to the end

Here is the explanation of what I'm trying to say:-
Input:- 5 1 3 2 7
Output:- 3
Explanation:
In first move, we move 3 to the end. Our list becomes 5,1,2,7,3
In second move, we move 5 to the end. Our list becomes 1,2,7,3,5
In third move, we move 7 to the end. Our final list = 1,2,3,5,7
So, total moves are:- 3.
Here is what I tried to do, but failed.
a = [int(i) for i in input().split()]
count = 0
n = 0
while (n < len(a) - 1):
for i in range(0,n+1):
while (a[i] > a[i + 1]):
temp = a[i]
a.pop(i)
a.append(temp)
count += 1
n += 1
print(count, end='')
I'd like to request your assistance in helping in solving this question.
jdehesa's answer is basically right, but not optimal for cases, when there is more element of same value. Maybe more complex solution?
def min_moves(a):
c = 0
while(1):
tmp = None
for i in range(0, len(a)):
if a[i] != min(a[i:]) and (tmp is None or a[i] < a[tmp]):
tmp = i
if tmp is None:
return c
else:
a.append(a.pop(tmp))
c += 1
Edit:
Or if you don't need ordered list, there's much more easier solution just to count items that are out of order for the reason from jdehesa's solution :-D
def min_moves(a):
c = 0
for i in range(0, len(a)):
if a[i] != min(a[i:]):
c += 1
return c
Edit 2:
Or if you like jdehesa's answer more, small fix is to reduce lst to set, so it will get smallest index
sorted_index = {elem: i for i, elem in enumerate(sorted(set(lst)))}
I cannot comment yet.
I don't know if it can be done better, but I think the following algorithm gives the right answer:
def num_move_end_sort(lst):
# dict that maps each list element to its index in the sorted list
sorted_index = {elem: i for i, elem in enumerate(sorted(lst))}
moves = 0
for idx, elem in enumerate(lst):
if idx != sorted_index[elem] + moves:
moves += 1
return moves
print(num_move_end_sort([5, 1, 3, 2, 7]))
# 3
The idea is as follows. Each element of the list would have to be moved to the end at most once (it should be easy to see that a solution that moves the same element to the end more than once can be simplified). So each element in the list may or may not need to be moved once to the end. If an element does not need to be moved is because it ended up in the right position after all the moves. So, if an element is currently at position i and should end up in position j, then the element will not need to be moved if the number of previous elements that need to be moved, n, satisfies j == i + n (because, after those n moves, the element will indeed be at position j).
So in order to compute that, I sorted the list and took the indices of each element in the sorted list. Then you just count the number of elements that are not in the right position.
Note this algorithm does not tell you the actual sequence of steps you would need to take (the order in which the elements would have to be moved), only the count. The complexity is O(n·log(n)) (due to the sorting).
I think you can simplify your problem,
Counting elements that need to be pushed at the end is equivalent to counting the length of the elements that are not in sorted order.
l = [5, 1, 3, 2, 7]
sorted_l = sorted(l)
current_element = sorted_l[0]
current_index = 0
ans = 0
for element in l:
if current_element == element:
current_index += 1
if current_index < len(l):
current_element = sorted_l[current_index]
else:
ans += 1
print(ans)
Here the answer is 3

Why can't I implement merge sort this way

I understand mergesort works by divide and conquer, you keep halving until you reach a point where you can sort in constant time or the list is just one lement and then you merge the lists.
def mergesort(l):
if len(l)<=1:
return l
l1 = l[0:len(l)//2+1]
l2 = l[len(l)//2:]
l1 = mergesort(l1)
l2 = mergesort(l2)
return merge(l1,l2)
I have a working merge implementation and I checked it works fine but the merge sort implementation does not work it just returns half of the elements of the list.
I see on the internet mergesort is implemented using l & r and m = (l + r)/2. What is wrong with my implementation? I am recursively subdividing the list and merging too.
the problem is the +1 in your code, here:
l1 = l[0:len(l)//2]
l2 = l[len(l)//2:]
replace this with your code and you're be fine
The code you have listed doesn't appear to do any sorting. I can't know for certain because you haven't listed the merge() function's code, but the only thing that the above function will do is recursively divide the list into halves. Here is a working implementation of a merge sort:
def mergeSort(L):
# lists with only one value already sorted
if len(L) > 1:
# determine halves of list
mid = len(L) // 2
left = L[:mid]
right = L[mid:]
# recursive function calls
mergeSort(left)
mergeSort(right)
# keeps track of current index in left half
i = 0
# keeps track of current index in right half
j = 0
# keeps track of current index in new merged list
k = 0
while i < len(left) and j < len(right):
# lower values appended to merged list first
if left[i] < right[j]:
L[k] = left[i]
i += 1
else:
L[k] = right[j]
j += 1
k += 1
# catch remaining values in left and right
while i < len(left):
L[k] = left[i]
i += 1
k += 1
while j < len(right):
L[k] = right[j]
j += 1
k += 1
return L
Your function makes no comparisons of values in the original list. Also, when you are splitting the list into halves in:
l1 = l[0:len(l)//2 + 1]
the '+ 1' is unnecessary (and can actually cause incorrect solutions). You can simply use:
l1 = l[:len(l)//2]
If the length is even (i.e 12) it will divide the two halves from [0:6] and [6:12]. If it is odd it will still automatically divide correctly (i.e. length = 13 would be [0:6] and [6:13]. I hope this helps!

Categories

Resources