Leetcode- Search Insert Position

来源:互联网 发布:王家卫风格的话知乎 编辑:程序博客网 时间:2024/06/06 17:37

算法描述:

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0

LeetCode链接:https://oj.leetcode.com/problems/search-insert-position/

算法解析:

   本算法要求:给定一个有序数组和目标值,能够快速的找到目标值在该有序数组中的位置(即索引,注意数组的索引是从0开始的),而且这个数组可以认为是没有重复数字的。通过分析,我们知道,无论目标值在给定数组中是否存在,都要返回一个有效索引值,而且要保证将目标值插入后数组还是有序的。

   笔者喜欢一切从简单入手,不行了在逐步往复杂的方面想,因此我首先想到的是顺序查找算法,从前到后遍历数组,直到找到位置结束。解决方案如下:

class Solution {public:    int searchInsert(int A[], int n, int target) {        int i = 0;        while((target > A[i]) && (i < n))        {            i++;        }        if (i == n)        {            return n;        }        else        {            return i;        }    }};

  
性能分析:    

   按照上面的解决方案,AC可以通过,结果如下图所示:

   从分析结果可以看出,该方案,测试了62个案例,总共运行了52ms,那对于该方法,还有没有可以改进的地方呢!仔细分析一下,其实有些临界点是不需要循环,比如:当目标值比数组中最小的值还小时(当然这种情况不影响性能,因为不会执行循环);当目标值比数组中最大的值还要大时,这种情况就会遍历一遍数组。因此,只要我们对临界条件分开处理,使循环提早结束,应该是可以改进性能的。改进后的解决方案如下:

class Solution {public:    int searchInsert(int A[], int n, int target) {        if (target <= A[0])        {            return 0;        }        else if (target == A[n - 1])        {            return n - 1;        }        else if (target > A[n - 1])        {            return n;        }        int i = 1;        while((target > A[i]) && (i < n))        {            i++;        }               return i;    }};


   AC分析结果如下:

   从结果可以看出,同样是解析62个案例,时间缩短到了40ms,虽然说对于某一特定的案例性能未必提高,但是如果你的应用中需要大量的使用该算法,那样的话性能的提高还是极其可观的。

其他实现思路:

   其实本算法就是对查找算法的应用,上面的方法是顺序查找算法的应用,当然也可以使用折半查找的思路来实现该算法。解决方案如下:

class Solution {public:    int searchInsert(int A[], int n, int target) {        if (target <= A[0])     //目标比最小的数还小的情况        {            return 0;        }        else if (target > A[n - 1])     //目标比最大的数还大的情况        {            return n;        }        int low = 0;        int high = n;        int middle = (low + high) / 2;        while (low < high)        {            if (target == A[middle])    //找到了直接输出,结束循环            {                return middle;            }            else if (target < A[middle])            {                high = middle - 1;            }            else            {                low = middle + 1;            }            middle = (low + high) / 2;        }                if (low == high)        //判断循环结束条件:如果low!=high说明循环是因为找到了目标才退出,反之说明目标在数组中不存在        {            if (target > A[low])            {                return low + 1;            }            else            {                return low;            }        }    }};

   那么折半查找的性能如何呢,我们知道,顺序查找的时间复杂度是O(n),而折半查找的时间复杂度为O(log2(n)),按理说折半查找的性能应该比顺序查找要好的多,实际如何呢!我们看一下AC的结果吧,如下:

   从AC的结果,我们可以看出时间仍然是40ms,这是为什么呢?因为,本算法只是借助于折半查找的思路,而实际上查找算法是不要求数组有序的,而且折半查找的性能是无序的情况下最高,当然还有其他因素,如AC中的案例的特征等。

 Python解决方案:

   顺序查找python解决方案如下:

class Solution:    # @param A, a list of integers    # @param target, an integer to be inserted    # @return integer    def searchInsert(self, A, target):        length = len(A)        if target > A[length - 1]:            return length;        elif target <= A[0]:            return 0;        i = 1;        while target > A[i]:            i += 1        return i        


   AC结果如下:


   python折半查找对应实现方案:

class Solution:    # @param A, a list of integers    # @param target, an integer to be inserted    # @return integer    def searchInsert(self, A, target):        length = len(A)        if target > A[length - 1]:            return length        elif target <= A[0]:            return 0        low = 0        high = length        middle = (low + high) / 2                while low < high:            if target == A[middle]:                return middle            elif target > A[middle]:                low = middle + 1            else:                high = middle            middle = (low + high) / 2                    if low == high:            if target > A[low]:                return low + 1            else:                return low


   AC结果如下:

   这里,笔者只给出结果,大家分析一下,会有惊喜发现啊!!!

0 0