I was working on a GFG question
Question:
Given two unsorted arrays arr1[] and arr2[]. They may contain duplicates. For each element in arr1[] count elements less than or equal to it in array arr2[].
Example 1:
Input:
m = 6, n = 6
arr1[] = {1,2,3,4,7,9}
arr2[] = {0,1,2,1,1,4}
Output: 4 5 5 6 6 6
Explanation: Number of elements less than
or equal to 1, 2, 3, 4, 7, and 9 in the
second array are respectively 4,5,5,6,6,6
Example 2:
Input:
m = 5, n = 7
arr1[] = {4 8 7 5 1}
arr2[] = {4,48,3,0,1,1,5}
Output: 5 6 6 6 3
Your Task :
Complete the function countEleLessThanOrEqual() that takes two array arr1[], arr2[], m, and n as input and returns an array containing the required results(the count of elements less than or equal to it in arr2 for each element in arr1 where ith output represents the count for ith element in arr1.)
Expected Time Complexity: O((m + n) * log n).
Expected Auxiliary Space: O(1).
Constraints:
1<=m,n<=10^5
1<=arr1[i],arr2[j]<=10^5
My python solution:
def countEleLessThanOrEqual(arr1,n1,arr2,n2):
#returns the required output
res=[]
arr2.sort()
for i in range(n1):
search=arr1[i]
count=0
start=0
end=n2-1
while(start<=end):
mid = int(start+(end-start)/2)
if search==arr2[mid]:
start=mid+1
elif search>arr2[mid]:
start=mid+1
elif search<arr2[mid]:
end=mid-1
count=end+1
res.append(count)
return res
When I submit it, it gives me TLE error even though my solution is similar to the one posted in the editorial:
Editorial solution:
# python implementation of For each element in 1st
# array count elements less than or equal to it
# in 2nd array
# function returns the index of largest element
# smaller than equal to 'x' in 'arr'. For duplicates
# it returns the last index of occurrence of required
# element. If no such element exits then it returns -1
def bin_search(arr, n, x):
l = 0
h = n - 1
while(l <= h):
mid = int((l + h) / 2)
# if 'x' is greater than or equal to arr[mid],
# then search in arr[mid + 1...h]
if(arr[mid] <= x):
l = mid + 1;
else:
# else search in arr[l...mid-1]
h = mid - 1
# required index
return h
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(arr1, arr2, m, n):
# sort the 2nd array
arr2.sort()
# for each element in first array
for i in range(m):
# last index of largest element
# smaller than or equal to x
index = bin_search(arr2, n, arr1[i])
# required count for the element arr1[i]
print(index + 1)
# driver program to test above function
arr1 = [1, 2, 3, 4, 7, 9]
arr2 = [0, 1, 2, 1, 1, 4]
m = len(arr1)
n = len(arr2)
countElements(arr1, arr2, m, n)
# This code is contributed by Aditi Sharma
You could use a binary search on the second array after sorting it in place:
from bisect import bisect_right
def lowerCount(arr1,arr2):
arr2.sort()
return [bisect_right(arr2,v) for v in arr1]
print(*lowerCount([1,2,3,4,7,9],[0,1,2,1,1,4])) # 4 5 5 6 6 6
print(*lowerCount([4, 8, 7, 5, 1],[4,48,3,0,1,1,5])) # 5 6 6 6 3
Sorting arr2 is O(N log N), and binary searches will take O(M log N) for a total of O( (N+M) log N ).
If you can't use libraries, you could always write your own bisect_right function:
def bisect_right(A,x):
lo,hi = 0,len(A)-1
while lo <= hi:
mid = (lo+hi)//2
if A[mid] <= x: lo = mid+1
else: hi = mid-1
return hi+1
#AasthaJha, would you like to try this similar but simplified alternative version:
def bin_search(A, n, x):
low, high = 0, n-1
while low <= high:
mid = (low + high) // 2
# if 'x' is greater than or equal to A[mid],
# then search in arr[mid + 1...h]
if A[mid] <= x:
low = mid + 1;
else:
high = mid -1 # else search in A[l...mid-1]
return high
# function to count for each element in 1st array,
# elements less than or equal to it in 2nd array
def countElements(A, B, m, n):
B.sort()
result = []
# loop element in A - first array
for i in range(m):
# last index of largest element smaller than or equal to x
index = bin_search(B, n, A[i])
print(index + 1) # count
result.append(index + 1)
return result
# Testing
A = [1, 2, 3, 4, 7, 9]
B = [0, 1, 2, 1, 1, 4]
m, n = len(A), len(B)
print(countElements(A, B, m, n))
Related
I am trying to solve problem 4.1 on Codility.com. I need a solution which runs in O(N) time. My code solves the problem, but it runs in O(N^2) time, according to Codility's performance tests. Unfortunately I can't see why. There is only one for loop, which should scale linearly with n.
The challenge is to write a solution which tests whether an array ('A') contains all integers between 1 and X. It should return the index of the element which is the last element in 1 to X that appears in the array, or it should return -1 if not every integer between 1 and X is an element of the array. For example, the solution to X = 4 and A = [1, 3, 4, 2, 2] is 3 since 2 is the last element in 1 to 4 which appears in the array and it first appears in position 3. The solution to X = 5 and A = [1, 2, 4, 2, 3] is -1 because 5 never appears. My solution is below.
def Solution(X, A):
N = len(A)
count = [0] * (X + 1)
# Solution for single-element arrays
if N == 1:
if A[0] == 1:
return 0
elif A[0] != 1:
return - 1
# Solution for multi-element arrays
elif N != 1:
for i in range(0, N + 1, 1):
if count[A[i]] == 0:
count[A[i]] = count[A[i]] + 1
else:
pass
if count == [0] + [1] * (X):
return i
elif count != [0] + [1] * (X) and i == N - 1:
return -1
Would anyone know why it runs in O(N^2) time? Codility's performance tests confirm this, but as far as I can see this should run in O(kN) time since there is only one for loop. Any help is appreciated.
Something like this would work in O(n), you would have to adjust it to the exact question given:
def solution(x, a):
b = []
for v in a:
# the conditions
if (type(v) == int) and (v < x) and (v>1): b.append(v)
else: return -1
return b
# some examples
# this returns -1
a = [1,2,3,4,5.5,6]
x = solution(5,a)
print(x)
# this returns the the list [2, 3, 4]
a = [2,3,4]
x = solution(5,a)
print(x)
the reason why is because you can exit the list at the first fail with the return -1 statement.
This should be O(N): a single instantiation of a list of length X, one for-loop over A which does O(1) retrieval of single list items, and one single final search of the list for None values.
def solution(X, A):
pos = [None] * X
for i, n in enumerate(A):
if 1 <= n <= X:
if pos[n-1] is None:
pos[n-1] = i
return pos[n-1] if None not in pos else -1
print(solution(4, [1, 3, 4, 2, 2]))
print(solution(5, [1, 2, 4, 2, 3]))
print(solution(1000, reversed(range(1, 1001))))
prints:
3
-1
999
I have array of M elements. I should find maximum sum of my array, which is less than integer number "N". All the elements in array are positive integers bigger or equal to zero. Also, sum can be non-consistent.
FOR example:
let's say M is = [1,2,3,6,0, 8, 9, 12] and N = 20, so here the answer is 20
but if M = [1,5,4,6] and N = 13, the answer is 12 - the maximum sum of array which is less than N
Problem: Find max sum from weights array, within maxCapacity
Approach: Problem is same as 0/1 Knapsack.
0/1 Knapsack problem:
Given: maxCapacity (int), weights (array) and values (array).
Find: max "value" by choosing items with total weight within
maxCapacity.
In this question:
Given: maxCapacity (int) and weights (array).
Find: max "weight" by choosing items with total weight within
maxCapacity.
Difference:
So unlike knapsack we have to maximise weight
instead of values. Thus, weight array will work as values array here.
def func(weights, maxCapacity):
knapsack = [[0 for i in range(len(weights) + 1)] for j in range(maxCapacity + 1)]
for w in range(maxCapacity + 1):
for i in range(len(weights) + 1):
if i == 0 or w == 0:
knapsack[w][i] = 0
elif weights[i - 1] <= w:
knapsack[w][i] = max(
weights[i - 1] + knapsack[w - weights[i - 1]][i - 1],
knapsack[w][i - 1],
)
else:
knapsack[w][i] = knapsack[w][i - 1]
for r in knapsack:
print(r)
return knapsack[-1][-1]
func([4, 8, 5, 9], 20)
Summary: Learn to solve 0-1 Knapsack Problem to understand this better.
First we need to check if the numbers sum is smaller than N, then save the sum as the result and the sum as the string at different lists at the same time.
So when we find the max in the list of sums is smaller than N, we can access the second list containing the strings using the same index.
M = [12, 9, 8, 4, 8, 5]
Ma = []
Ma_num = []
N = 20
for i in M:
for a in range(len(M)):
if i + M[a] <= N:
Ma.append(f"{i} + {M[a]}")
Ma_num.append(i + M[a])
max_num = Ma_num.index(max(Ma_num))
print(Ma[max_num])
Output:
12 + 8
By the way, if you meant that you wanted to see the number 20 in output, the solution is this:
M = [12, 9, 8, 4, 8, 5]
Ma = []
N = 20
for i in M:
for a in range(len(M)):
if i + M[a] <= N:
Ma.append(i + M[a])
max_num = max(Ma)
print(max_num)
Output:
20
I have a solution, first sum all number in your m array then in a loop check
sum >=n
if true return m
else sum = m - min(m)
and remove min
and check again
##############################3
check this solotion
M = [1,2,3,6,0, 8, 9, 12]
n = 20
s= 0
while s < n:
maximum = max(M)
M.remove(maximum)
if (s+ maximum)>n:
continue
s = s + maximum
print(s)
This can be solved as a Knapsack Problem
In the Knapsack problem we have a vector of values (val) and weights (wt)
We want to maximize the sum of a subset of values (val) such that
the corresponding weight is less than some max (referred to as capacity)
We can use the Knapsack algorithm by:
(1) Letting the input array corresponds to both weights and values
(2) Maximum capacity is the max sum
Code for solving Knapsack from here
def knapSack(W , wt , val, n):
# Base Case
if n == 0 or W == 0 :
return 0
# If weight of the nth item is more than Knapsack of capacity
# W, then this item cannot be included in the optimal solution
if (wt[n-1] > W):
return knapSack(W , wt , val , n-1)
# return the maximum of two cases:
# (1) nth item included
# (2) not included
else:
return max(val[n-1] + knapSack(W-wt[n-1] , wt , val , n-1),
knapSack(W , wt , val , n-1))
def max_sum(K, arr):
'''Solve using Knapsack code with (set weights and values equal to arr)'''
return knapSack(K, arr, arr, len(arr))
Test
arr = [1,5,4,6]
print(max_sum(13, arr))
#>>> Outputs 12
arr =[1,2,3,6,0, 8, 9, 12]
print(max_sum(20, arr))
#>>> Outputs 20
arr = [2,5,6,8]
print(max_sum(17, arr))
#>>> Outputs 16
Complexity
The time complexity of Knapsack solution is O(nW)
where n is the length of the array arr
W is the max sum
I need to print out n indexes of elements of list that after multiplying equal to some given integer. It's guaranteed that the combination exists in a list. For example, for the following input(number of elements in array, multiplication wanted number, number of elements in wanted sublist and given array):
7 60 4
30 1 1 3 10 6 4
I should get in any order
1 2 4 5
Because 1*1*10*6==60. If there are more than 1 solution I need to print any of them.
My solution works but pretty slow, how can I make it work faster?
from itertools import chain, combinations
arr = list(map(int, input().split()))
numbers = list(map(int, input().split()))
s = sorted(numbers)
def filtered_sublists(input_list, length):
return (
l for l in all_sublists(input_list)
if len(l) == length
)
def all_sublists(l):
return chain(*(combinations(l, i) for i in range(len(l) + 1)))
def multiply(arr):
result = 1
for x in arr:
result = result * x
return result
def get_indexes(data):
indexes = []
for i in range(len(data)):
if arr[1] == multiply(data[i]):
for el in data[i]:
if numbers.index(el) in indexes:
all_ind = [i for i, x in enumerate(numbers) if x == el]
for ind in all_ind:
if ind not in indexes:
indexes.append(ind)
break
else:
indexes.append(numbers.index(el))
break
return indexes
sublists = list(filtered_sublists(numbers, arr[2]))
print(*get_indexes(sublists))
The key is don't test every combination.
def combo(l, n=4, target=60, current_indices=[], current_mul=1):
if current_mul > target and target > 0:
return
elif len(current_indices) == n and current_mul == target:
yield current_indices
return
for i, val in enumerate(l):
if (not current_indices) or (i > current_indices[-1] and val * current_mul <= target):
yield from combo(l, n, target, current_indices + [i], val * current_mul)
l = [30,1,1,3,10,6,4]
for indices in combo(l, n=4, target=60):
print(*indices)
Prints:
1 2 4 5
More testcases:
l = [1,1,1,2,3,3,9]
for c, indices in combo(l, n=4, target=9):
print(*indices)
Prints:
0 1 2 6
0 1 4 5
0 2 4 5
1 2 4 5
We can use a memoized recursion for an O(n * k * num_factors), solution, where num_factors depends on how many factors of the target product we can create. The recurrence should be fairly clear from the code. (Zeros aren't handled but those should be pretty simple to add extra handling for.)
Pythonesque JavaScript code:
function f(A, prod, k, i=0, map={}){
if (i == A.length || k == 0)
return []
if (map[[prod, k]])
return map[[prod, k]]
if (prod == A[i] && k == 1)
return [i]
if (prod % A[i] == 0){
const factors = f(A, prod / A[i], k - 1, i + 1, map)
if (factors.length){
map[[prod, k]] = [i].concat(factors)
return map[[prod, k]]
}
}
return f(A, prod, k, i + 1, map)
}
var A = [30, 1, 1, 3, 10, 6, 4]
console.log(JSON.stringify(f(A, 60, 4)))
console.log(JSON.stringify(f(A, 60, 3)))
console.log(JSON.stringify(f(A, 60, 1)))
You could start from the target product and recursively divide by factors in the remaining list until you get down to 1 and after using the specified number of factors. This has the advantage of quickly eliminating whole branches of recursion under numbers that are not a factor of the target product.
Handling zero values in the list and a target product of zero requires a couple of special conditions at the start and while traversing factors.
For example:
def findFactors(product, count, factors, offset=0):
if product == 0: return sorted((factors.index(0)+i)%len(factors) for i in range(count))
if not count: return [] if product == 1 else None
if not factors: return None
for i,factor in enumerate(factors,1):
if factor == 0 or product%factor != 0: continue
subProd = findFactors(product//factor,count-1,factors[i:],i+offset)
if subProd is not None: return [i+offset-1]+subProd
r = findFactors(60, 4, [30,1,1,3,10,6,4])
print(r) # [1, 2, 4, 5]
r = findFactors(60, 4, [30,1,1,0,3,10,6,4])
print(r) # [1, 2, 5, 6]
r = findFactors(0, 4, [30,1,1,3,10,6,0,4])
print(r) # [0, 1, 6, 7]
I have an array and I want to find the longest number sequence from the array that does not contain 3:
#array
x=[1,2,3,4,5,6,5,4,3,3,4,5,2,3,7]
I expect as result as following:
[4, 5, 6, 5, 4]
If I were doing this, I would make groups with itertools.groupby and take the longest one:
from itertools import groupby
a = [1,2,3,4,5,6,5,4,3,3,4,5,2,3,7]
groups = [list(g) for k, g in groupby(a, key=lambda x: x!=3) if k]
max(groups, key = len)
# [4, 5, 6, 5, 4]
Of course there are many other way. If you want to manually loop through the list, you can just keep track of the current longest seen:
a = [1,2,3,4,5,6,5,4,3,3,4,5,2,3,7]
cur = []
longest = cur
for n in a:
if n != 3:
cur.append(n)
if len(cur) > len(longest):
longest = cur
else:
cur = []
print(longest) #[4, 5, 6, 5, 4]
If you want to find sequence (specifically subsequence) then taking all elements which are not 3 will be the result.
But it seems you want to find sub array. Following is my implementation for the same in python
def findLargestSubArray(arr, k):
# collect all the index position of k in arr
kPos = [i for i in range(len(arr)) if arr[i] == k]
largest = 0
left = -1
right = -1
# size of subarray to the left of 1st instance of k
if len(kPos) > 0:
largest = kPos[0] - 1
left = 0
right = kPos[0]
for i in range(1, len(kPos)):
# size of subarray between ith & (i-1)th instance of k
currSize = kPos[i] - kPos[i-1] - 1
if largest < currSize:
largest = currSize
left = kPos[i-1] + 1
right = kPos[i]
# size of subarry to the right of last instance of k
if largest < len(arr) - kPos[-1] - 1:
largest = len(arr) - kPos[-1] - 1
left = kPos[-1] + 1
right = len(arr)
return arr[left: right]
x = [3,3]
print(findLargestSubArray(x, 3))
In the following sequence, each number (except the first two) is the sum of the previous two number: 0, 1, 1, 2, 3, 5, 8, 13, .... This sequence is known as the Fibonacci sequence.
Given the positive integers m and n (with m < n) create a list consisting of the portion of the Fibonacci sequence greater than or equal to m and less than or equal to n. For example, if m is 3 and n is 6, then the list would be [3, 5] and if m is 2 and n is 20, then the list would be [2, 3, 5, 8, 13].
Associate the list with the variable fib.
Have done this far, but still getting error.
Where does it need to be fixed?
fib = [0,1,1]
result = 0
while result <=n:
result=fib[-1]+fib[-2]
if result <=n and result>=m:
fib.append(result)
# create a fibonacci series from 0 to n
f = [0,1]
for i in range(1, n+1):
x = f[i]+f[i-1]
if x > n:
break
else:
f.append(x)
# copy only those numbers of series that are in range m to n
fib = []
for i in range(0, len(f)):
if f[i] >= m and f[i] <= n:
fib.append(f[i])
You could use the code below.
fib = [0,1,1]
fibrange = [] # keeps your digits that are in range m < n
result = 0
n = 80
m = 2
while result <=n:
result =fib[-1]+fib[-2]
fib.append(result)
if result <=n and result>=m:
fibrange.append(result)
print fibrange
fib=[0,1]
i=0
while i <=n:
i=fib[-1]+fib[-2]
if i<=n:
fib.append(i)