Maximum value from contiguous part of a list - python-3.x

How can I find maximum value from a part of list. Means if I want to know maximum number from index i to j then is there any in built method to do so.

A simple example, define a list with five elements, print the max from the second until the third index.
max is a built-in function.
max:
Return the largest item in an iterable or the largest of two or more
arguments.
l = [1,2,3,4,5]
print (max(l[2:3]))

Related

Find largest set of lines which are parallel but not colinear

I have a 5 lines below with each line representing a,b,c in ax+by+c = 0
1 0 0
1 2 3
3 4 5
30 40 0
30 40 50
I want to find the largest set of non colinear parallel lines from these lines. The result in the above case will be:-
set of 2 lines
3 4 5
30 40 0
The brute force approach would be to go through all the possible combinations which would be O(n*(n+1)/2) and update the largest possible set after each iteration.
Is there any way to find the set size faster?
A solution would be to transform the coordinates into (angle, distance from origin). Finding the largest set will then be O(nlogn).
Assuming that (a,b) are never both 0, find the distance to origin d using d = c/|(a,b)|. Then, find the angle θ using θ = atan2(b,a). You then have a list of coordinates that looks like this:
[[θ0,d0],
[θ1,d1],
...
]
Sort this list using θ as the key.
Remove all elements that you consider colinear given a threshold. Simply parse the list to check if some pairs of consecutive elements have approximately the same value. Do not forget to test the last element with the first element to account for 360° = 0°. If you encounter a colinear pair, remove one of the element.
Using a minimum and maximum index starting at 0, increase the maximum index until the difference between the first angle (at min index) and the last angle (at max index) pass the angle tolerance that you can accept as being parallel (do not forget to consider that 359.999° is close to 0°). If the size of the set (max index - min index) is bigger than your current best set, note it as the current best. Then, increase the minimum index by one and continue increasing the maximum index until the angle difference test fail again. Continue to do so until the minimum index reaches the end of the list and do not forget to make the maximum index wrap to 0 to consider the cases close to 0° and 360°.
To make it easier to find the elements in the user provided list, you can add the original index to the transformed list, e.g., [[θ0,d0,0],[θ1,d1,1],...].
Some implementation details to consider to avoid making it accidentally O(n^2): Removing an element from an contiguous array is O(n), so instead of removing colinear elements every time you encounter one, note the index in a separate list and recreate the array in a second pass. If you instead use a linked list, the min/max index should be replaced by iterators to avoid the O(n) random access using an index to access an element.

Optimization of Python comprehension expression

I was trying to get the frequency of max value in an integer list (intlist)
intlist.count(max(intlist))
this works and is good in speed as well.
I wanted to implement the max method with comprehension,-
[x if x>y else y for x in intlist for y in intlist if x!=y][-1]
the later turns out to be very slow.
Can any one point out what is the issue here.
testing with
intlist=np.array([1, 2, 3,3,-1])
in this case the value expected is 2 as 3 is the max value and it occurs 2 times.
The list comprehension will not calculate the maximum value in the first place. Indeed, it will here calculate the maximum of two values from intlist of the latest values. So unless the last two items in the list are the same, it will calculate the maximum of the last two values.
Furthermore it is not very efficient, since it runs in O(n2) time, and O(n2) memory. For huge lists, this would thus require gigantic amounts of memory.
Usually it is not a good idea to use list comprehension if you do not need a list in the first place. You can calculate a maximum with a for loop, where you each time compare an item with the thus far obtained maximum:
def other_max(listlike):
mmax = listlike[0]
for x in listlike:
if x > mmax:
mmax = x
return mmax
or with numpy we can sum up the array of booleans:
>>> (intlist == intlist.max()).sum()
2

How can you randomly return an element from a list?

in this question we are asked to randomly return an element from a list. where "rand()" is uniformly distributed from 0 to 1. "list" is a list of elements
def r(lst):
return lst[int(random.uniform(a=0,b=1)*len(lst))]
However random.choice() is easier to use
https://docs.python.org/3/library/random.html
You should mention in the question if there are multiple answers to choose from.
return list[int(len(list)*rand())]
This is the correct answer. Multiplying the number of elements len(list) with a random number between 0 and 1 gives you a random number between 0 and len(list). You use int() to convert the value to an integer, effectively rounding it down and then select the item at that position.
return list[(len(list)/rand())]
This doesn't work. len(list) will usually be an integer > 1 and dividing that by a number between 0 and 1 always gives an even bigger number, so you always try to get an item that is after the last one in the list. Also the index will be a float, but the index must be an integer
return list[int(rand()) # i assume you wanted to use a square bracket here
This will always select the first element. It's a random number between 0 and 1 rounded down => 0
return list[len(list)} # same thing here
this will always try to select the element after the last one, which results in an error. Also, this can't even be random without the rand() function ...

Time complexity of my backtracking to find the optimal solution of the maximum sum non adjacent

I'm trying to do dynamic programming backtracking of maximum sum of non adjacent elements to construct the optimal solution to get the max sum.
Background:
Say if input list is [1,2,3,4,5]
The memoization should be [1,2,4,6,9]
And my maximum sum is 9, right?
My solution:
I find the first occurence of the max sum in memo (as we may not choose the last item) [this is O(N)]
Then I find the previous item chosen by using this formula:
max_sum -= a_list[index]
As in this example, 9 - 5 = 4, which 4 is on index 2, we can say that the previous item chosen is "3" which is also on the index 2 in the input list.
I find the first occurence of 4 which is on index 2 (I find the first occurrence because of the same concept in step 1 as we may have not chosen that item in some cases where there are multiple same amounts together) [Also O(N) but...]
The issue:
The third step of my solution is done in a while loop, let's say the non adjacent constraint is 1, the max amount we have to backtrack when the length of list is 5 is 3 times, approx N//2 times.
But the 3rd step, uses Python's index function to find the first occurence of the previous_sum [which is O(N)] memo.index(that_previous_sum)
So the total time complexity is about O(N//2 * N)
Which is O(N^2) !!!
Am I correct on the time complexity? Or am I wrong? Is there a more efficient way to backtrack the memoization list?
P.S. Sorry for the formatting if I done it wrong, thanks!
Solved:
I looped from behind checking if the item in front is same or not
If it's same, means it's not first occurrence. If not, it's first occurrence.
Tada! No Python's index function to find from the first index! We find it now from the back
So the total time complexity is about O(N//2 * N)
Now O(N//2 + 1), which is O(N).

Binary search - worst/avg case

I'm finding it difficult to understand why/how the worst and average case for searching for a key in an array/list using binary search is O(log(n)).
log(1,000,000) is only 6. log(1,000,000,000) is only 9 - I get that, but I don't understand the explanation. If one did not test it, how do we know that the avg/worst case is actually log(n)?
I hope you guys understand what I'm trying to say. If not, please let me know and I'll try to explain it differently.
Worst case
Every time the binary search code makes a decision, it eliminates half of the remaining elements from consideration. So you're dividing the number of elements by 2 with each decision.
How many times can you divide by 2 before you are down to only a single element? If n is the starting number of elements and x is the number of times you divide by 2, we can write this as:
n / (2 * 2 * 2 * ... * 2) = 1 [the '2' is repeated x times]
or, equivalently,
n / 2^x = 1
or, equivalently,
n = 2^x
So log base 2 of n gives you x, which is the number of decisions being made.
Finally, you might ask, if I used log base 2, why is it also OK to write it as log base 10, as you have done? The base does not matter because the difference is only a constant factor which is "ignored" by Big O notation.
Average case
I see that you also asked about the average case. Consider:
There is only one element in the array that can be found on the first try.
There are only two elements that can be found on the second try. (Because after the first try, we chose either the right half or the left half.)
There are only four elements that can be found on the third try.
You can see the pattern: 1, 2, 4, 8, ... , n/2. To express the same pattern going in the other direction:
Half the elements take the maximum number of decisions to find.
A quarter of the elements take one fewer decision to find.
etc.
Since half of the elements take the maximum amount of time, it doesn't matter how much less time the other elements take. We could assume that all elements take the maximum amount of time, and even if half of them actually take 0 time, our assumption would not be more than double whatever the true average is. We can ignore "double" since it is a constant factor. So the average case is the same as the worst case, as far as Big O notation is concerned.
For binary search, the array should be arranged in ascending or descending order.
In each step, the algorithm compares the search key value with the key value of the middle element of the array.
If the keys match, then a matching element has been found and its index, or position, is returned.
Otherwise, if the search key is less than the middle element's key, then the algorithm repeats its action on the sub-array to the left of the middle element.
Or, if the search key is greater,then the algorithm repeats its action on the sub-array to the right.
If the remaining array to be searched is empty, then the key cannot be found in the array and a special "not found" indication is returned.
So, a binary search is a dichotomic divide and conquer search algorithm. Thereby it takes logarithmic time for performing the search operation as the elements are reduced by half in each of the iteration.
For sorted lists which we can do a binary search, each "decision" made by the binary search compares your key to the middle element, if greater it takes the right half of the list, if less it will take the left half of the list (if it's a match it will return the element at that position) you effectively reduce your list by half for every decision yielding O(logn).
Binary search however, only works for sorted lists. For un-sorted lists you can do a straight search starting with the first element yielding a complexity of O(n).
O(logn) < O(n)
Although it entirely depends on how many searches you'll be doing, your inputs, etc what your best approach would be.
For Binary search the prerequisite is a sorted array as input.
• As the list is sorted:
• Certainly we don't have to check every word in the dictionary to look up a word.
• A basic strategy is to repeatedly halve our search range until we find the value.
• For example, look for 5 in the list of 9 #s below.v = 1 1 3 5 8 10 18 33 42
• We would first start in the middle: 8
• Since 5<8, we know we can look at just the first half: 1 1 3 5
• Looking at the middle # again, narrow down to 3 5
• Then we stop when we're down to one #: 5
How many comparison is needed: 4 =log(base 2)(9-1)=O(log(base2)n)
int binary_search (vector<int> v, int val) {
int from = 0;
int to = v.size()-1;
int mid;
while (from <= to) {
mid = (from+to)/2;
if (val == v[mid])
return mid;
else if (val > v[mid])
from = mid+1;
else
to = mid-1;
}
return -1;
}

Resources