3

Question as follows:

An array is said to be cyclically sorted if it is possible to cyclically shift its entries so that it becomes sorted. For example, the array in Figure 11.2 is cyclically sorted - a cyclic left shift by 4 leads to a sorted array. Design an O(logN) algorithm for finding the position of the smallest element in a cyclically sorted array. Assume all elements are distinct. For example, for the list = [378, 478, 550, 631, 103, 203, 220, 234, 279, 368] the return value should be 4.

The solution works by comparing the mid value against the A[n-1] - depending on the relation you can narrow down the search to the side of the list with the inflection.

My solution:

def cyclic_sorted_lst(A):
  low, high = 0, len(A) - 1
  while low <= high:
    mid = (low + high) // 2
    if A[mid] < A[high]:
      high = mid 
    elif A[mid] == A[high]:
      return mid 
    else:
      low = mid + 1 

Author solution:

def search_smallest(A):
  left, right = 0, len(A) - 1 
  while left < right:
    mid = (left + right) // 2
    if A[mid] > A[right]:
      left = mid + 1 
    else:
      right = mid 
  return left 

I'm wondering if my solution would cause any off-by-one errors, or if the two solutions are equally good. Is there anything I'm missing with mine? It works well, at least, for the example in the problem description.

segue_segway
  • 1,490
  • 1
  • 22
  • 40
  • It is simpler and faster to test these kind of things rather than analyse them critically. Simply generate arrays randomly and compare the output of your solution to a simple linear scan through the array! Doing this will take barely five minutes and you will be satisfied with the quality of your solution. – xrisk Jun 02 '18 at 19:51
  • 1
    @Rishav That is the worst possible advice you can give somebody. It's that kind of thinking that gets me woke up at 2 AM because the web site went down. Some short-sighted person threw some code together without analyzing it critically, ran it through a few tests and said, "Well, it seems to work. Let's ship it." I shudder to think that somebody working on, say, self-driving cars would follow your advice. – Jim Mischel Jun 03 '18 at 04:23

1 Answers1

-1

Following my comment, I wrote a simple test generator to test your solution. Here is the code:

def cyclic_sorted_lst(A):
  low, high = 0, len(A) - 1
  while low <= high:
    mid = (low + high) // 2
    if A[mid] < A[high]:
      high = mid 
    elif A[mid] == A[high]:
      return mid 
    else:
      low = mid + 1

import random
i = 0
while True:
    i += 1
    print(i)
    arr = list(set([random.randint(1, int(1000)) for _ in range(10)]))
    arr.sort()
    length = random.randint(1, len(arr))
    cyclic_arr = arr[length:] + arr[:length]
    print(cyclic_arr)
    if cyclic_sorted_lst(cyclic_arr) != cyclic_arr.index(min(cyclic_arr)):
        print(cyclic_arr, cyclic_sorted_lst(cyclic_arr), cyclic_arr.index(min(cyclic_arr)))
        break

Your code ran successfully for over 200K iterations so I am pretty confident it is correct.

xrisk
  • 3,790
  • 22
  • 45
  • Absolutely not! All this does it prove that you haven't found a failing case. There is an infinite number of possible arrays. No amount of testing will prove that the algorithm will work for every case. Random testing is not a substitute for algorithm analysis. I once ran into a critical bug that occurred very rarely. It took *years* for somebody to encounter the bug and track it down. Fortunately, the bug just took down my web crawler rather than taking out an electrical power grid or something. See https://stackoverflow.com/q/1148278/56778 for details. – Jim Mischel Jun 03 '18 at 04:33