finding contiguous Subset with Largest Sum - python

def max_sublist(x):
max1 = 0
max2 = 0
result = []
for i in x:
max2 = max(0, max2 + i)
max1 = max(max1, max2)
print result
I want to add elements till the element which had the max sum. How do I add only whose elements to the result.
For ex. if x = [4, -1, 5, 6, -13, 2]
then result should be [4, -1, 5, 6]

This is a classic problem in optimization, and it's called the maximum subarray problem. Here's one possible dynamic programming solution in O(n), using Kadane's algorithm:
def max_val_contiguous_subsequence_idxs(seq):
i = thisSum = maxSum = 0
startIdx, endIdx = 0, -1
for j in xrange(len(seq)):
thisSum += seq[j]
if thisSum > maxSum:
maxSum = thisSum
startIdx = i
endIdx = j
elif thisSum < 0:
thisSum = 0
i = j + 1
return (maxSum, startIdx, endIdx)
The above will return in a single pass a tuple with the maximum sum, the starting index and the end index of the subsequence. For example, using the sample input in the question:
lst = [4, -1, 5, 6, -13, 2]
maxSum, startIdx, endIdx = max_val_contiguous_subsequence_idxs(lst)
maxSum
=> 14
lst[startIdx:endIdx+1]
=> [4, -1, 5, 6]
Notice that the implementations shown in the wikipedia page (which look a lot like the solution you were aiming for) only give the maximum sum, but unlike my solution they don't tell you how to find the subsequence indexes in the array.

Related

Counting elements in 2 arrays (GFG)

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))

Building max heap using python i'm encountered with wrong output

i'm trying to build max heap in python i have done but after heapify the list output is not satisfy the max heap property.
Can any one help to fix this issue
def max_heapify(arr,i):
left = 2 *i
right = 2 * i + 1
length = len(arr)-1
largest = i
if length > left and arr[largest] < arr[left]:
largest = left
if length > right and arr[largest] < arr[right]:
largest = right
if largest != i:
arr[largest],arr[i] = arr[i],arr[largest]
max_heapify(arr,largest)
def build_max_heap(arr):
for i in reversed(range(len(arr)//2)):
max_heapify(arr,i)
return arr
arr = [1,12,9,5,6,10]
print(build_max_heap(arr))
i'm getting out put [12, 9, 6, 5, 1, 10] which is not satisfy max heap property
There are two issues:
First, the heap is 0-based (the root is at index zero), so the children of node 0 will be 1 and 2, and hence the children of node i will be 2*i+1 and 2*i+2
Your code compared the two children before swapping, but it has not compared the larger child with the parent, and it should only swap if the child is larger than the parent
def max_heapify(arr,i):
left = 2 *i + 1
right = 2 * i + 2
length = len(arr)
largest = i
if length > left and arr[largest] < arr[left]:
largest = left
if length > right and arr[largest] < arr[right]:
largest = right
if arr[largest] > arr[i]:
arr[largest], arr[i] = arr[i],arr[largest]
max_heapify(arr,largest)
def build_max_heap(arr):
N = len(arr)
for i in reversed(range(len(arr)//2)):
max_heapify(arr,i)
return arr
arr = [1,12,9,5,6,10]
print(build_max_heap(arr))
arr = [1,12,9,5,6,10,13]
print(build_max_heap(arr))
output:
[12, 6, 10, 5, 1, 9]
[13, 12, 10, 5, 6, 1, 9]

Finding Maximum non-negative Subarray in python

I've tried to find the sub-array(s) from a given which contain elements of maximum sum than any other sub array.
Below function has parameter as input a and the output needs to be returned. There can be more than one subarray as their maximum sum can be equal. The code did not seem to be working as expected.
def max_sum_subarray(a):
N, sub_sum, max_sum, subArrays = len(a), 0, 0, {}
p,q=0,0 #starting and ending indices of a max sub arr
for i in range(N):
q=i
sub_sum+=a[i]
if(a[i]<0):
q-=1
if(sub_sum>=max_sum):
if(sub_sum>max_sum):
subArrays.clear()
subArrays[sub_sum]=[(p,q)]
else:
subArrays[sub_sum].append((p,q))
sub_sum=0
p=i+1
if(sub_sum>=max_sum):
if(sub_sum>max_sum):
subArrays.clear()
subArrays[sub_sum]=[(p,q)]
else:
subArrays[sub_sum].append((p,q))
return(subArrays[p:q+1])
When I tried to run for input
a=[ 1, 2, 5, -7, 2, 5 ]
Expected output is [1, 2, 5] but it gave [2, 5] instead. Can anyone please post the solution in python?
It seems like you making this harder than necessary. You can just keep track of max array seen to far and the current one you're pushing into -- you don't really need to care about anything else. When you hit a negative (or the end of the array) decide if the current should be the new max:
def maxSub(a):
max_so_far = []
max_sum = 0
cur = []
for n in a:
if n >= 0:
cur.append(n)
else:
cur_sum = sum(cur)
if cur_sum > max_sum:
max_sum = cur_sum
max_so_far = cur
cur = []
return max([max_so_far, cur], key = sum)
a=[ 1, 2, 5, -7, 2, 5 ]
maxSub(a)
# [1, 2, 5]
Of course itertools.groupby makes this a one-liner:
from itertools import groupby
a=[ 1, 2, 5, -7, 2, 5 ]
max([list(g) for k,g in groupby(a, key=lambda x: x>0) if k == True], key=sum)
For the following conditions:
NOTE 1: If there is a tie, then compare with segment’s length and
return segment which has maximum length
NOTE 2: If there is still a tie, then return the segment with minimum
starting index
Here is my working code in python:
def check(max_arr,curr):
if sum(curr) > sum(max_arr):
max_arr = curr
elif sum(curr) == sum(max_arr):
if len(curr) > len(max_arr):
max_arr = curr
elif len(curr) == len(max_arr):
if max_arr and (curr[0] > max_arr[0]):
max_arr = curr
return max_arr
def maxset(A):
curr = []
max_arr = []
for i in A:
if i >= 0:
curr.append(i)
else:
max_arr = check(max_arr,curr)
curr = []
max_arr = check(max_arr,curr)
return max_arr

Find longest sequence that does not contain a certain number

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))

Reducing a N-Sum to a Two Sum

I've recently came across a cool algorithm to reduce any problem of the sort "Find n numbers in an array that sum to a target" to a Two Sum problem. However, I am having a hard time understanding one line of the code.
def findNsum(nums, target, N, result, results):
if len(nums) < N or N < 2 or target < nums[0]*N or target > nums[-1]*N: # early termination
return
if N == 2: # two pointers solve sorted 2-sum problem
l,r = 0,len(nums)-1
while l < r:
s = nums[l] + nums[r]
if s == target:
results.append(result + [nums[l], nums[r]])
l += 1
while l < r and nums[l] == nums[l-1]:
l += 1
elif s < target:
l += 1
else:
r -= 1
else: # recursively reduce N
for i in range(len(nums)-N+1):
if i == 0 or (i > 0 and nums[i-1] != nums[i]):
findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results)
results = []
findNsum(sorted(nums), 0, 3, [], results)
return results
The condition:
if i == 0 or (i > 0 and nums[i-1] != nums[i]):
Does not make sense to me. Why do I have to check if nums[i-1] != nums[i]? If I try it out with, say, with nums = [-1, 0, 1, 2, 2, -1, -4], I get [[-4, 2, 2], [-1, -1, 2], [-1, 0, 1]] with the condition. If I take it out I get [[-4, 2, 2], [-1, -1, 2], [-1, 0, 1], [-1, 0, 1]]. Can any one make sense of this?
Cheers!
The condition nums[i-1] != nums[i] is to avoid creating duplicate solutions when picking the first element, which can see in your output in the second example. This problem wants to find all unique solutions, not all possible solutions, hence we want to drop the second [-1,0,1]

Categories

Resources