3

Given a list that can be broken into two pieces L[:z] and L[z:] such that the first is non-increasing and the second is non-decreasing and may or may not contain duplicate elements, create a function such that:


Input:

  • A list L as specified above
  • A value k which represents the maximum number of times any given value is repeated in the list

Output:

  • The minimum value of the list

Complexity & Requirements

  • O(log n)
  • Can only use built in library functions not including min/max

I have the following:

def findmin(L, k = None):
    left = 0
    right = len(L)-1
    foundmin = False

    while not foundmin:
        mp = (left + right)//2
        if L[mp] > L[mp+1]:
            left = mp
        elif L[mp-1] < L[mp]:
            right = mp+1
        else:
            return L[mp]

It only works for some lists such as: L = [9,9,4,3,2,1,7,7,10,10]

But it does not work correctly for lists such as: L = [6,5,4,3,3,3,3,3,3,3,3,3,1,7,7,7,7]

I have tried modifying the function to accommodate repeated elements to no avail. I am also not seeing the utility of the input k for the function. Thoughts?

  • why aren't you using `min(L)`. It gives you the minimum value in the list. You can divide the list in `n` numbers and then compare these `n` values after you add them to a list. – Shivkumar Birnale Oct 15 '18 at 04:59
  • @ShivkumarBirnale because the requested time complexity of the problem is O(logn) and `min(L)` runs in O(n) – bergerg Oct 15 '18 at 05:02
  • @ShivkumarBirnale I am trying to learn how to work with lists without relying too heavily on the library functions. Also the complexity of min/max is O(n) which will not work for my application. – Devon_Letendre Oct 15 '18 at 05:02
  • 1
    Binary search is the answer. But you should probably be checking the boundary elements of your array, because that is the solution to finding the shift point of a cyclically shifted sorted array, and the input to your problem suggests the two are quite similar in nature. Also, consider using the value of K somehow? – cs95 Oct 15 '18 at 05:34
  • @coldspeed I attempted to use k to compare k+1 values in the list sequentially, but this only led to more complications. I think the idea was to check subsets of size k+1 until you find one that is both increasing and decreasing, and then you would know that the minimum value is in that subset and you could narrow it down from there. – Devon_Letendre Oct 15 '18 at 05:41

2 Answers2

2

This code runs in O(logn) and has no use of the k parameter.

It is some kind of binary search like @coldspeed commented.

def find_min(l, k=None):
    left = 0
    right = len(l) - 1
    while left <= right:
        middle = (left + right) // 2
        if l[middle] < l[left] or (l[middle] == l[left] and middle > left):
            left = middle
        elif l[middle] < l[right] or (l[middle] == l[right] and middle < right):
            right = middle
        else:
            return l[middle]
bergerg
  • 985
  • 9
  • 23
1

The issue with your solution is that if the numbers on either side of mp are equal to mp, then your algorithm will output L[mp]. Thus, in the second case, it outputs 3. A simple thing would be be check the next unequal number instead of checking just the adjacent ones.

Modified solution :

def findmin(L, k = None):
    left = 0
    right = len(L)-1
    foundmin = False

    while left<right:
        print(left, right)
        mp = (left + right)//2
        next_diff = mp+1
        while(next_diff < len(L)-1 and L[next_diff] == L[mp]):
            next_diff+=1
        if L[mp] > L[next_diff]:
            left = next_diff
        elif L[mp] <= L[next_diff]:
            right = mp
    return L[left]

P.S : Though the complexity in this case becomes O(k* log n).

Deepak Saini
  • 2,810
  • 1
  • 19
  • 26
  • This appears to be correct and works for both lists. I see where I was going wrong now by trying to check adjacent values only. From what I understand about Big O notation, constants get dropped, so this becomes O(log n) anyways. – Devon_Letendre Oct 15 '18 at 05:37
  • @Devon_Letendre, Glad it helped. Yes, k gets dropped if you consider it to be a constant. Since, you mentioned that you expect it as an input, so generally params taken as inputs aren't considered constants. Please consider upvoting and/or accepting. – Deepak Saini Oct 15 '18 at 05:40