2

I am trying to find a fixed point in an array using a function that only accepts one input (an array). The problem is, I'm trying to avoid building another function that this function can call. If I could do that, this situation would be solved. These arrays will contain a list of sorted integers for me to iterate through. I am trying to keep its runtime low by using binary search. I've tried this a 100 different ways, and nothing is quite working.

def fixed_point(a):    

    if len(a) <= 2: # tried len(a) == 0 and len(a) == 1
        return -1 

    mid = len(a)//2 # have used (len(a)-1)//2 as well

    if mid == a[mid]:
        return a[mid]

    if mid > a[mid]:
        return find_point(a[mid+1:])

    else:
        return find_point(a[:mid])

    return -1

This function will return -1 if no fixed point is found.

This function also passes 10000 tests built for this, but for some reason cannot find that "5" is the fixed point of array: [-10, -5, -2, 2, 3, 5, 7, 10, 15, 25, 35, 78, 129]

Curious as to what people might find wrong with this code.

duplode
  • 31,361
  • 7
  • 69
  • 130
n3vdawg
  • 29
  • 6
  • Ugh, I'm an idiot. I removed "fixed" for it to be easier to read just for this post. Otherwise, this typo is not found in my original code. I have been at this for hours. I'll fix that – n3vdawg Jun 03 '18 at 01:46
  • The `mid` that you're looking for is the midpoint with respect to the original array, right? When you slice the list and pass it in for the next call, the size changes so none of your if conditions are going to hold true after, because the mid you're looking for, and the mid you end up comparing will not be the same. – cs95 Jun 03 '18 at 01:47
  • By the way, my understanding of "fixed point" is that the index of a value is equal to the value... right? – cs95 Jun 03 '18 at 01:48
  • Hm, that makes sense. I guess I need to think about how I could fix that.... – n3vdawg Jun 03 '18 at 01:48
  • Yes, the index of a value needs to be equal to its value @coldspeed – n3vdawg Jun 03 '18 at 01:49
  • My advice is to not go with recursion here. – cs95 Jun 03 '18 at 01:50
  • @JohnZwinck Yeah, I realized that the moment I did that. Should have just copied the entire thing and pasted it word for word from my editor – n3vdawg Jun 03 '18 at 01:51
  • @coldspeed No recursion? Alright I'll see what I can do instead. Thank you. – n3vdawg Jun 03 '18 at 01:51

2 Answers2

1

To repeat what I said in my comment, the problem is that you're losing track of a.

Your approach is recursive, and you pass a list with shrinking size at each call. Because of this, the mid you're looking for, and the mid you end up comparing aren't the same.

Switch to an iterative approach, and you can keep things within the context of the original a.

def fixed_point(a):
    l, u = 0, len(a)

    while l <= u:
        m = (l + u) // 2
        if m == a[m]:
            return m
        elif m > a[m]:
            l = m + 1
        else:
            u = m - 1

    return -1

>>> fixed_point([-10, -5, -2, 2, 3, 5, 7, 10, 15, 25, 35, 78, 129])
5

Iteration also has the benefit of having lesser overhead in terms of memory (no need for call stacks), although on other languages, some compilers will optimise.

cs95
  • 274,032
  • 76
  • 480
  • 537
0

The fundamental problem with your algorithm as written is that you lose track of where you are in the original array. When you recurse, you return the fixed point of half of the array, but for example in [-4, -2, 0, 2, 4] when you split the array and find the fixed point in [2, 4] it doesn't work, because there is no fixed point in [2, 4]. You need to pass an offset into each recursive call, so you can say something like if mid + offset == a[mid].

John Zwinck
  • 207,363
  • 31
  • 261
  • 371
  • Can't believe I would overlook something like that. I really appreciate the clarification on how I was wrong in my approach. Thank you. – n3vdawg Jun 03 '18 at 01:58