I want change order in arr if the next element is bigger than current.
Hot to modify the code, so it will be work?
arr = [5, 22, 29, 39, 19, 51, 78, 96, 84]
i = 0
while (i < arr.size-1)
if arr[i].to_i < arr[i+1].to_i
arr[i]
elsif arr[i].to_i > arr[i + 1].to_i
arr[i+1], arr[i] = arr[i], arr[i+1]
end
puts arr[i]
i += 1
end
Returns: [5, 22, 29, 39, 19, 51, 78, 96, 84]
Instead: [5, 19, 22, 29, 39, 51, 78, 84, 96]
You can use any of sorting algorithms depending on the size of array (n),
For Bubble Sort, Time Complexity is O(n^2)
For Merge Sort, Time Complexity is O(nlogn)
For Counting Sort, Time Complexity is O(n) but number in array must be 0.upto 10^6
Bubble Sort: It runs pairwise in one iteration and put the maximum element in last, In second iteration, put the second maximum element in second last position and so on till array is sorted.
Iterate (n-1) times [to find (n-1) max numbers]
Iterate (n-idx-1) times to swap pair of numbers if (first number is
greater than next number)
If swapping stopped in inner loop means that array becomes sorted,
so break the outer loop
Ruby Code:
def bubble_sort(arr)
n = arr.size
(n-1).times do |idx|
swapped = false
(n-idx-1).times do |i|
if arr[i] > arr[i+1]
arr[i], arr[i+1] = arr[i+1], arr[i]
swapped = true
end
end
break unless swapped
end
arr
end
p bubble_sort([5, 22, 29, 39, 19, 51, 78, 96, 84])
Merge Sort: It runs on divide and conquer strategy, i.e if you know two halves of array is sorted then you can sort whole array by using two pointer strategy in O(n).
For Instance,
#first half : [4,5,7,9]
#second half : [1,2,10,15]
1. Take two pointer l and r assigned to starting index of both halves i.e 0
2. Iterate over l and r upto their lengths to consume both arrays
if element at first_half[l] < second_half[r]
Put first_half[l] in result_array
Increment l pointer
else
Put second_half[r] in result_array
Increment r pointer
This merge operation will take O(n) to sort whole array.
Now, if we divide whole array into two halves recursively, we will get binary tree of height log(n) and each level will take O(n) to sort the subproblems (halves), resulting in O(nlogn) Time Complexity.
Base case would be : single element array is always sorted
Ruby Code:
def merge(left_sorted, right_sorted)
res = []
left_size, right_size = left_sorted.size, right_sorted.size
l = r = 0
loop do
break if r == right_size and l == left_size # break if both halves processed
if r == right_size or (l < left_size and left_sorted[l] < right_sorted[r])
res << left_sorted[l]; l += 1
else
res << right_sorted[r]; r += 1
end
end
res
end
def merge_sort(arr)
size = arr.size
return arr if size <= 1 # base case
mid = arr.size/2 - 1
left_half, right_half = arr[0..mid], arr[mid+1..-1]
left_sorted = merge_sort(left_half)
right_sorted = merge_sort(right_half)
return merge(left_sorted, right_sorted)
end
p merge_sort([5, 22, 29, 39, 19, 51, 78, 96, 84])
Counting Sort: It works in O(n) by counting numbers appearance in array if numbers in array lies in range(0..10^6)
Keep count of each number of array in count_array.
Iterate from min_element to max_element of array, and put element in
sorted_array if appeared i.e its count > 0
Ruby Code:
def counting_sort(arr)
min, max = arr.min, arr.max
count_arr = [0] * (max - min + 1) # initialize count_array with all 0s
arr.each do |num|
count_arr[num - min] += 1
end
res = []
size = count_arr.size
size.times do |i|
count_arr[i].times do
res << i + min
end
end
res
end
p counting_sort([5, 22, 29, 39, 19, 51, 78, 96, 84])
Notice that as you sort you are rearranging the array. Don't modify it, use it as a reference and place the sorted items in a new array.
If you want to study algotirthms use C or C++.
def bubble_sort(array)
sorted = array.dup
i = 0
l = sorted.length
while i < (l - 1)
j = 0
while j < l - i - 1
if sorted[j] > sorted[j + 1]
tmp = sorted[j]
sorted[j] = sorted[j + 1]
sorted[j + 1] = tmp
end
j += 1
end
i += 1
end
sorted
end
puts bubble_sort([5, 22, 29, 39, 19, 51, 78, 96, 84])
Related
I feel like I'm close but not quite sure why my while loop stops executing, I want it to run/ increase the counter then the conditions are true, then when it runs into numbers out of order, swap them, then decrease the counter, then run the while loop again until all the numbers are in order. So like it slides the number that's out of order backwards until it's higher than the number before it but lower than then number after it. If that makes sense.Probably an easy one for most of you but I'm just new to python. Here is my code so far;
arr = [7, 14, 21, 32, 17, 48, 69, 78, 72]
count = 0
while (count < len(arr) - 1) and (arr[count] < arr[count+1]):
count += 1
if (arr[count] > arr[count+1]):
arr[count], arr[count+1] = arr[count+1], arr[count]
count -= 1
continue
print(count)
print(arr)
below my code with some pseudocode to make it clearer.
# list of numbers out of order
arr = [7, 14, 21, 32, 17, 48, 69, 78, 72]
# first position in index
count = 0
# loop to check first if value of index position is less than length of array -1 (9-1 = 8)
# or if value of index position is less than index position + 1 (next index position)
while (count < len(arr) - 1) and (arr[count] < arr[count+1]):
# if true loop should continue + 1 on the next index
count += 1
# if the value of number in the current index position is greater than the next number it swaps them.
if (arr[count] > arr[count+1]):
arr[count], arr[count+1] = arr[count+1], arr[count]
count -= 1
continue
print(count)
print(arr)
I've tried various different things, I think I'm just stuck on how while loops actually work and I need to get the loop to run again after it hits it's first false statement.
This would work in the way that is required in the question:
finds the first two numbers that are out of order.
switched those numbers only and exit.
arr = [7, 14, 21, 32, 17, 48, 69, 78, 72]
for i, v in enumerate(arr):
if i == len(arr) -1:
print('reached the end')
break
if v > arr[i+1]:
print('out of order index', i, 'value:',v)
# do the switch
arr[i], arr[i+1] = arr[i+1], v
break
print(arr)
the result is this:
out of order index 3 value: 32
[7, 14, 21, 17, 32, 48, 69, 78, 72]
You could also achieve the same with a while loop so long as a break condition existed.
Here is first question on stackoverflow :)
consider a random array composed of any integers
a = [5, 10, 2, 3, 56]
I would like to write a code that will compare each element likewise: element of index i (el_i) with element of index i + 1 (el_i+1) (and continue comparison with element index i + 1 (el_i+1) with element of index i + 2 (el_i+2) till a.length). Then I would like to sum elements according to the result of the comparison. Here is an example of a failed attempt to picture it:
def conditional_sum(array)
sum = 0
array.each_with_index do |element, i|
if array[i] >= array[i + 1]
sum += element
else
sum -= element
end
end
sum
end
Another consisted in making 2 arrays from the previous one and delete the last element (I spare you the code to obtain them) an compare elements that have the same index likewise:
a = [5, 10, 2, 3, 56]
a_bis = [5, 10, 2, 3]
b = [10, 2, 3, 56]
sum = 0
for i in [0..a_bis.length]
if a_bis[i] >= b[i]
sum += a_bis[i] + b[i]
else
sum -= a_bis[i] + b[i]
end
end
p sum
doesn't work either... Many thanks for your help!
If I understood your question:
a = [5, 10, 2, 3, 56]
a.each_cons(2).sum do |first, second|
first > second ? first - second : first + second
end
#=>87
#each_cons will group them into pairs of consecutive elements:
a.each_cons(2) do |pair|
p pair
end
#=>[5, 10]
# [10, 2]
# [2, 3]
# [3, 56]
Then you can execute the desired calculation for each pair inside the block.
your first example was almost working. Trying it raise the error:
`>=': comparison of Integer with nil failed (ArgumentError)
It come from the fact that for the last iteration of the index, you compare the last value 56 with nil. Ie 56 >= nil has no sense for ruby, therefore the error. To fix it, you can iterate without the last element. As always in ruby, their are multiple ways to do it. Here is mine :
def conditional_sum(array)
sum = 0
# array[0...-1] will iterate without le last element
array[0...-1].each_with_index do |element, i|
if array[i] >= array[i + 1]
sum += element
else
sum -= element
end
end
sum
end
Another solution to do what you want would be the following (more functional style). Using the #each_cons to select each pair
def conditional_sum(array)
array.each_cons(2)
.sum {|i,j| i >= j ? i : -i}
end
We have an array of N positive elements. We can perform M operations on this array. In each operation we have to select a subarray(contiguous) of length W and increase each element by 1. Each element of the array can be increased at most K times.
We have to perform these operations such that the minimum element in the array is maximized.
1 <= N, W <= 10^5
1 <= M, K <= 10^5
Time limit: 1 sec
I can think of an O(n^2) solution but it is exceeding time limit. Can somebody provide an O(nlogn) or better solution for this?
P.S.- This is an interview question
It was asked in a Google interview and I solved it by using sliding window, heap and increment in a range logic. I will solve the problem in 3 parts:
Finding out the minimum of every subarray of size W. This can be done in O(n) by using sliding window with priority queue. The maximum of every window must be inserted into a min-heap with 3 variable: [array_value, left_index, right_index]
Now, make auxiliary array initialised to 0 with of size N. Perform pop operation on heap M number of times and in each pop operation perform 3 task:
value, left_index, right_index = heap.pop() # theoretical function to pop minimum
Increment the value by 1,
increment by 1 in auxiliary array at left_index and decrement by 1 in
auxiliary array at right_index+1
Again insert this pair into heap. [with incremented value and same indexes]
After performing M operations traverse the given array with auxiliary array and add the cumulative sum till index 'i' to element at index 'i' in array.
Return minimum of array.
Time Complexity
O(N) <- for minimum element in every window + building heap.
O(M*logN) <- Extracting and inserting into heap.
O(N) <- For traversing to add cumulative sum.
So, overall is O(N + M*logN + N) which is O(M*logN)
Space Complexity
O(N) <- Extra array + heap.
Few things can be easily optimised above like inserting values in heap, only left_index can be inserted and as right_index = left_index + k.
My Code
from heapq import heappop, heappush
from collections import deque
def find_maximised_minimum(arr, n, m, k):
"""
arr -> Array, n-> Size of array
m -> increment operation that can be performed
k -> window size
"""
heap = []
q = deque()
# sliding window + heap building
for i in range(k):
while q and arr[q[-1]] > arr[i]:
q.pop()
q.append(i)
for i in range(k, n):
heappush(heap, [arr[q[0]], i - k, i - 1])
while q and q[0] <= i - k:
q.popleft()
while q and arr[q[-1]] > arr[i]:
q.pop()
q.append(i)
heappush(heap, [arr[q[0]], n - k, n - 1])
# auxiliary array
temp = [0 for i in range(n)]
# performing M increment operations
while m:
top = heappop(heap)
temp[top[1]] += 1
try:
temp[top[2] + 1] -= 1
except:
# when the index is last, so just ignore
pass
top[0] += 1
heappush(heap, top)
m -= 1
# finding cumulative sum
sumi = 0
for i in range(n):
sumi += temp[i]
arr[i] += sumi
print(min(arr))
if __name__ == '__main__':
# find([1, 2, 3, 4, 5, 6], 6, 5, 2)
# find([73, 77, 60, 100, 94, 24, 31], 7, 9, 1)
# find([24, 41, 100, 70, 97, 89, 38, 68, 41, 93], 10, 6, 5)
# find([88, 36, 72, 72, 37, 76, 83, 18, 76, 54], 10, 4, 3)
find_maximised_minimum([98, 97, 23, 13, 27, 100, 75, 42], 8, 5, 1)
What if we kept a copy of the array sorted ascending, pointing each element to its original index? Think about the order of priority when incrementing the elements. Also, does the final order of operations matter?
Once the lowest element reaches the next lowest element, what must then be incremented? And if we apply k operations to any one element does it matter in which w those increments were applied?
Below is some code I submitted for a array sum algorithm. In this case I had to use .each but I feel like there is a better way to do this...
numbers = [5, 17, 2, 899, 101, 4, 66, 123, 98]
sum = 0
index = 0
numbers.each do |number|
sum = sum + numbers[index]
index += 1
end
puts sum
There is. You don't need to track index manually when using each; you can simply do
numbers.each do |number|
sum = sum + number
end
I have a table of values stored into a list of lists like:
A = [ [a[1],b[1],c[1]],
[a[2],b[2],c[2]],
...
[a[m],b[m],c[m]]]
with
a[i] < b[1]
b[i] < a[i+1]
0 < c[i] < 1
and a numpy array such as:
X = [x[1], x[2], ..., x[n]]
I need to create an array
Y = [y[1], y[2], ..., y[n]]
where each value of Y will correspond to
for i in [1,2, ..., n]:
for k in [1,2, ..., m]:
if a[k] < x[i] < b[k]:
y[i] = c[k]
else:
y[i] = 1
Please note that X and Y have the same length, but A is totally different. Y can take any value in the third column of A (c[k] for k= 1,2,... m), as long as a[k] < x[i] < b[k] is met (for k= 1,2,... m and for i= 1,2,... n).
In the actual cases I am working on, n = 6789 and m = 6172.
I could do the verification using nested "for" cycles, but it is really slow. What is the fastest way to accomplish this? what if X and Y where 2D numpy arrays?
SAMPLE DATA:
a = [10, 20, 30, 40, 50, 60, 70, 80, 90]
b = [11, 21, 31, 41, 51, 61, 71, 81, 91]
c = [ 0.917, 0.572, 0.993 , 0.131, 0.44, 0.252 , 0.005, 0.375, 0.341]
A = A = [[d,e,f] for d,e,f in zip(a,b,c)]
X = [1, 4, 10.2, 20.5, 25, 32, 41.3, 50.5, 73]
EXPECTED RESULTS:
Y = [1, 1, 0.993, 0.132, 1, 1, 1, 0.375, 1 ]
Approach #1: Using brute-force comparison with broadcasting -
import numpy as np
# Convert to numpy arrays
A_arr = np.array(A)
X_arr = np.array(X)
# Mask that represents "if a[k] < x[i] < b[k]:" for all i,k
mask = (A_arr[:,None,0]<X_arr) & (X_arr<A_arr[:,None,1])
# Get indices where the mask has 1s, i.e. the conditionals were satisfied
_,C = np.where(mask)
# Setup output numpy array and set values in it from third column of A
# that has conditionals satisfied for specific indices
Y = np.ones_like(X_arr)
Y[C] = A_arr[C,2]
Approach #2: Based on binning with np.searchsorted -
import numpy as np
# Convert A to 2D numpy array
A_arr = np.asarray(A)
# Setup intervals for binning later on
intv = A_arr[:,:2].ravel()
# Perform binning & get interval & grouped indices for each X
intv_idx = np.searchsorted(intv, X, side='right')
grp_intv_idx = np.floor(intv_idx/2).astype(int)
# Get mask of valid indices, i.e. X elements are within grouped intervals
mask = np.fmod(intv_idx,2)==1
# Setup output array
Y = np.ones(len(X))
# Extract col-3 elements with grouped indices and valid ones from mask
Y[mask] = A_arr[:,2][grp_intv_idx[mask]]
# Remove (set to 1's) elements that fall exactly on bin boundaries
Y[np.in1d(X,intv)] = 1
Please note that if you need the output as a list, you can convert the numpy array to a list with a call like this - Y.tolist().
Sample run -
In [480]: A
Out[480]:
[[139.0, 355.0, 0.5047342078960846],
[419.0, 476.0, 0.3593886192040009],
[580.0, 733.0, 0.3137694021600973]]
In [481]: X
Out[481]: [555, 689, 387, 617, 151, 149, 452]
In [482]: Y
Out[482]:
array([ 1. , 0.3137694 , 1. , 0.3137694 , 0.50473421,
0.50473421, 0.35938862])
With 1-d arrays, it's not too bad:
a,b,c = np.array(A).T
mask = (a<x) & (x<b)
y = np.ones_like(x)
y[mask] = c[mask]
If x and y are higher-dimensional, then your A matrix will also need to be bigger. The basic concept works the same, though.