Kadane's algorithm, maximum summation of consecutive elements - python

How can I keep track of the starting index of the maximum continuous sum problem?
index_pairs[] are the starting index [0] and the ending index [1] of the max cont. sum.
I can always find the last index of the maximum continuous
summation, but my starting index, index_pairs[0] will return
the incorrect index if there is a larger number after the maxsum.
My train of thought: In order to know the sum of the starting index, I must know
when maxendinghere is added from zero with the integers of my iterable list. However, when
maxendinghere will always be zero to zero if it is less than and is updated even if the next continuous
sum (may not be the largest sum) is being summed up.
Is there a way to find the starting index of my maximum continuous summation index
from random import randrange
iterable = [randrange(-10,10) for r in xrange(100)]
def max_continuous_sequence(iterable):
maxsum, maxendinghere = 0, 0
index_pairs = [0,0]
for i,x in enumerate(iterable):
# summing next numbers
maxendinghere += x
if maxsum < maxendinghere:
# found a higher sum
maxsum = maxendinghere
index_pairs[1] = i
elif maxendinghere < 0:
# resets the max here if next element is less than zero
maxendinghere = 0
# starts off the index at where we ended last
index_pairs[0] = i+1
return (index_pairs[0],index_pairs[1])

You could reverse the order of the elements, run your algorithm to compute the last index (which is really the first index of the initial sequence), and then compute how far it is from the end of the sequence to get the answer. Addition is commutative :)

Related

Finding which range of numbers has the most occurrence in a list

The complexity I have to follow is o(n) so I am not allowed to use nested loops. I have a rough idea on what I want to do however I am not sure how to store the lower bound of the range.
The objective is to find the lower bound for the interval that holds the most elements.
We denote L as the length of range. What I've tried is:
lst = [1,2,3,4,5,5,6,6,6,12] #after sorting by radix
L = 3
for i in range(len(lst)):
lower_bound[i] = i
upper_bound[i] = i + L #in this case L = 3.
#if i is in range of certain i and its upper_bound,
#increment count for that interval
# e.g. 1 is in range of 0-3, so count for lower_bound[1] will +1.
# e.g. 6 is in range of 4-6, so count for lower_bound[4] will +3.
#return the lower_bound with max count
So for this example, 3 will be returned, since 3-6 has 7 elements (prioritising the minimum lower bound).
I'm not sure if this is the right approach :( Does this look correct, given the complexity is o(n)?
If I understand your problem properly, it might be solved using two-pointers approach.
Set the left pointer (index) to the 0, then move right index until element difference between lst[right] and lst[left] becomes larger than L.
Remember index difference right - left
Move left index until element difference becomes smaller than L
Move right index again, compare new index difference with current one, get max.
Repeat until end of the list

Printing the max and max index within a range in a list

In the code below it randomly selects a range of numbers within the list_. Stop has to be greater than start, and than I want the program to output the maximum number within the list_[start:stop] as well as the order that number is at. I am having an issue printing the index of the functions between a range in the list_.
#15 numbers in the list
list_ = [1,3,5,6,7,2,3,6,4,3,5,7,8,11,10]
stop= random.randint(1, len(list_))
start = random.randint(0, stop)
maxnum = max(list_[start:stop])
max_index = list_.index(maxnum)
print("maximum number in range: ", maxnum, "index of max number: ", max_index)
The issue is that you have repeated number in list_. The .index method returns the index of the first instance of that it finds. If start=5 and stop=7, the max is 3 at index 6. But the returned index is 1 because you are finding the first 3 in the entire list.
You can get around this by using index on your sublist, then adding the start index. Though if there are repeats of the max value in your sublist, it will again return the first index.
max_index = list_[start:stop].index(maxnum) + start
Another (slightly more concise) way is to use start and stop parameters of the index method:
max_index = list_.index(maxnum, start, stop)

Find the indices of the two largest and two smallest values in a matrix in python

I am attempting to find the indices of the two smallest and the two largest values in python:
I have
import sklearn
euclidean_matrix=sklearn.metrics.pairwise_distances(H10.T,metric='euclidean')
max_index =np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))
min_index=np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))
min_index
max_index
I get the following output
(array([158, 272]), array([272, 158]))
(array([ 31, 150]), array([150, 31]))
the above code only returns the indices of the absolute smallest and the absolute largest values of the matrix, I would like to find the indices of the next smallest value and the indices of the next largest value. How can I do this? Ideally I would like to return the indices of the 2 largest values of the matrix and the indices of the two smallest values of the matrix. How can I do this?
I can think of a couple ways of doing this. Some of these depend on how much data you need to search through.
A couple of caveats: You will have to decide what to do when there are 1, 2, 3 elements only Or if all the same value, do you want min, max, etc to be identical? What if there are multiple items in max or min or min2, max2? which should be selected?
run min then remove that element run min on the rest. run max then remove that element and run on the rest (note that this is on the original and not the one with min removed). This is the least efficient method since it requires searching 4 times and copying twice. (Actually 8 times because we find the min/max then find the index.) Something like the in the pseudo code.
PSEUDO CODE:
max_index = np.where(euclidean_matrix==np.max(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(max_index) #syntax might not be right?
max_index2 = np.where(tmp_euclidean_matrix==np.max(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))
min_index = np.where(euclidean_matrix==np.min(euclidean_matrix[np.nonzero(euclidean_matrix)]))
tmp_euclidean_matrix = euclidean_matrix #make sure this is a deepcopy
tmp_euclidean_matrix.remove(min_index) #syntax might not be right?
min_index2 = np.where(tmp_euclidean_matrix==np.min(tmp_euclidean_matrix[np.nonzero(tmp_euclidean_matrix)]))
Sort the data (if you need it sorted anyway this is a good option) then just grab two smallest and largest. This isn't great unless you needed it sorted anyway because of many copies and comparisons to sort.
PSEUDO CODE:
euclidean_matrix.sort()
min_index = 0
min_index2 = 1
max_index = len(euclidean_matrix) - 1
max_index2 = max_index - 1
Best option would be to roll your own search function to run on the data, this would be most efficient because you would go through the data only once to collect them.
This is just a simple iterative approach, other algorithms may be more efficient. You will want to validate this works though.
PSEUDO CODE:
def minmax2(array):
""" returns (minimum, second minimum, second maximum, maximum)
"""
if len(array) == 0:
raise Exception('Empty List')
elif len(array) == 1:
#special case only 1 element need at least 2 to have different
minimum = 0
minimum2 = 0
maximum2 = 0
maximum = 0
else:
minimum = 0
minimum2 = 1
maximum2 = 1
maximum = 0
for i in range(1, len(array)):
if array[i] <= array[minimum]:
# a new minimum (or tie) will shift the other minimum
minimum2 = minimum
minimum = i
elif array[i] < array[minimum2]:
minimum2 = i
elif array[i] >= array[maximum]:
# a new maximum (or tie) will shift the second maximum
maximum2 = maximum
maximum = i
elif array[i] > array[maximum2]:
maximum2 = i
return (minimum, minimum2, maximum2, maximum)
edit: Added pseudo code

Find the maximum Index difference given constraints

In my quest on learning algorithm design, i started practicing questions and there is this particular questions that i have trouble with finding an efficient solution.
Given an array A of integers, find the maximum of j - i subjected to
the constraint of A[i] <= A[j]. A : [3 5 4 2] Output : 2 for the pair
(3, 4)
def maxIndex(arr):
max_val = float("-inf")
for i in range(0,len(arr)):
for j in range(i + 1 , len(arr)):
#print(arr[i],arr[j])
if arr[i] <= arr[j]:
diff_i = j - i
if diff_i > max_val:
max_val = diff_i
return max_val
A = [3, 5, 4, 2]
print("Result :",maxIndex(A))
My naive approach above will work but the time complexity is O(n^2) with a space complexity of O(1).
Here both the value and the indexes are important.IF i sort the list out of place and store the indices in a dictionary , i will still have to use a nested for loop to check for j - 1 constraint.
How can i improve the time complexity?
You can create two auxiliary array such that the min array stores at index i the minimum value till the index i, similarly the max array contains the max array value till index i (traversed in reverse)
You can find the answer here https://www.geeksforgeeks.org/given-an-array-arr-find-the-maximum-j-i-such-that-arrj-arri/
As has been mentioned, there is an O(n) solution which is the most efficient. I will add another way of solving it in O(n log n):
We can think of this problem as for each index i, know the furthest index j > i where a[i] <= a[j]. If we had this, we only need to evaluate the difference of the indexes and keep a maximum over it. So, how to calculate this information?
Add all elements to a set, in the form of a pair (element, index) so it first sorts by element, and then by index.
Now iterate the array backwards starting from last element. For every pair in the set where element is lower or equal to current element, we set its furthest index as current index and we remove it from set.
After all is done, evaluate the furthest index j of each i and the answer is the max of those
Note that for each element, we need to search in the set all values that are lower. The search is O(log n), and while we could iterate more, as we remove it later from the set we only end up iterating each element once, so the overall complexity is O(n log n).
A possible solution that I can think from the top of my head for the given problem would be to create a list of pair from the given list which preserves the list indices along with the list value, that is, list of (Ai, i) for all elements in the list.
You can sort this given list of pairs in ascending order and iterate from left-to-right. We maintain a variable which represents the minimum index we have encountered till now in our iteration min_index. Now at every step i, we update our answer as ans = max(ans, indexi - min_index) iff indexi > min_index and also our min_index and also our min_index as min_index = min(indexi, min_index) Since our list is sorted, it's guaranteed that A[i] >= A[min_index]
Since we need to sort the array initially, the overall complexity of the solution is O(nlog(n))
There is approach with O(nlogn) time (while I have feeling that linear algorithm should exist).
Make list min-candidates
Walk through the source list.
If current item is less than current minimum, add its index to min-candidates. So corresponding values are sorted in descending order.
If current item is larger than current minimum, search for the first less item in min-candidates with binary search. Find index difference and compare with the current best result.
This could be solved in O(nlogn) time and O(n) space.
Create a list of tuples of [value, index]
Sort them by value
Initialize min_index to some max value ( list.length + 1 )
Initialize a max value for difference of indices
Initialize a tuple to capture indices that has max difference.
Now go through following steps ( pseudo code ):
min_index = list.length + 1
max = 0
max_tuple = []
for tuple t in list:
min_index = minimum( t.index, min_index )
if ( t.index != min_index )
if ( t.index - min_index >= max )
max = t.index - min_index
max_tuple = [min_index, t.index]
In other words, you keep track of minimum index and because your list is sorted, as you go through the list in increasing value order, you will get a difference between the min index and your current index which you need to maximize.

finding the min value using loop python

I can find max value, I can find average but I just can't seem to find the min. I know there is a way to find max and min in a loop but right now I can only find the max.
def large(s)
sum=0
n=0
for number in s:
if number>n:
n=number
return n
Is there a way to find the min value using this function?
You can use Python's built-in sum(), min(), and max() functions for this kind of analysis.
However, if you're wanting to do it all in one pass or just want to learn how to write it yourself, then the process is 1) iterate over the input and 2) keep track of the cumulative sum, the minimum value seen so far, and the maximum value seen so far:
def stats(iterable):
'''Return a tuple of the minimum, average, and maximum values
>>> stats([20, 50, 30, 40])
(20, 35.0, 50)
'''
it = iter(iterable)
first = next(it) # Raises an exception if the input is empty
minimum = maximum = cumsum = first
n = 1
for x in it:
n += 1
cumsum += x
if x < minimum:
minimum = x
if x > maximum:
maximum = x
average = cumsum / float(n)
return minimum, average, maximum
if __name__ == '__main__':
import doctest
print doctest.testmod()
The code has one other nuance. It uses the first value from the input iterable as the starting value for the minimum, maximum, and cumulative sum. This is preferred over creating a positive or negative infinity value as initial values for the maximum and minimum. FWIW, Python's own builtin functions are written this way.
Finding the minimum takes the same algorithm as finding the maximum, but with the comparison reversed. < becomes > and vice versa. Initialize the minimum to the largest value possible, which is float("inf"), or to the first element of the list.
FYI, Python has a builtin min function for this purpose.
You must set n to a very high number (higher than any of the expected) or to take one from the list to start comparison:
def large(s)
n = s.pop()
for number in s:
if number < n:
n = number
return n
Obviously you have already max and min for this purpose.
A straightforward solution:
def minimum(lst):
n = float('+inf')
for num in lst:
if num < n:
n = num
return n
Explanation: first, you initialize n (the minimum number) to a very large value, in such a way that any other number will be smaller than it - for example, the infinite value. It's an initialization trick, in case the list is empty, it will return infinite, meaning with that that the list was empty and it didn't contain a minimum value.
After that, we iterate over all the values in the list, checking each one to see if it is smaller than the value we assumed to be the minimum. If a new minimum is found, we update the value of n.
At the end, we return the minimum value found.
Why not just replace large with small and > with <? Also, you might not want to initialize n to 0 if you're looking for the smallest value. Your large function only works for lists of positive numbers. Also, you're missing a ":" after your def line.
def small(s):
if len(s)==0: return None
n = s[0]
for number in s[1:]:
if n < number:
n=number
return n
This handles empty lists by returning None.
Using this function to find minimum is
min=-large(-s)
The logic is just to find maximum of the negative list , which gives the minimum value
You can use same function with iteration just instead of n=0 use n=L[0]
def min(L):
n=L[0]
for x in L:
if x
def min(s):
n=s[0]
for number in s:
if number < n:
n=number
return n

Categories

Resources