由如何找出数组中第二大的数引发的思考?

2,679 阅读3分钟

面试好多总会被问及排序问题,大多都是冒泡、二分、快速等,想想排序的原理,如果不深刻理解,面试的时候我自己都觉得自己蒙圈。。。比如冒泡排序,第一轮其实就能找到最大值,再找第二最大值怎么办?直接再来一轮,跟最大值比较呢?是否可以?因为要考虑算法复杂度的问题,假如数组很大,有重复数字的话,结果是否准确?我们怎么实现?

关键词第二最大、算法复杂度、准确

首先看一下冒泡排序

function getSecondBigNum(arr){    let temp;    for(let i = 0; i < 2; i++){        for(let j = 0; j < arr.length-1; j++){            if(arr[j]>arr[j+1]){                temp = arr[j]                arr[j] = arr[j+1]                arr[j+1] = temp            }        }    }    return arr[arr.length-2]}var arr = [8,6,2,7,3]console.log(getSecondBigNum(arr))

      两轮循环即可,时间复杂度为2n,效率还可以,使用数组[8,6,2,7,3]来测试返回结果也没有问题,但是忽略了一个细节,题目中没有说明数组中的值是不重复的,所以对于[8,8,6,2,7,3]来说,返回结果就是错误的。

      于是考虑两次迭代后判断最后两个值是否相等,如果相等再继续第三次冒泡排序,以此类推总能找到,但是面试官就问你了,你知道这样复杂度会怎样吗?极端情况下。数组很大,而且重复的有很多,那就是n2,效率太低。

      再想想,既然第一次迭代就找出最大值,那就把最大值移出去,剩下的在做一次冒泡时间复杂度3n,差不多可以接受。代码如下:

function getSecondBigNum(arr){    let temp;    let newArr = []    for(let j = 0; j < arr.length-1; j++){        if(arr[j]>arr[j+1]){            temp = arr[j]            arr[j] = arr[j+1]            arr[j+1] = temp        }    }    //把最大值去除,包括重复的最大值    for(let i = 0; i< arr.length-1;i++){        if(arr[i] != arr[arr.length-1]){            newArr[i] = arr[i]        }    }    for(let j = 0; j< newArr.length-1; j++) {        if(newArr[j]>newArr[j+1]){            temp = newArr[j]            newArr[j] = newArr[j+1]            newArr[j+1] = temp        }    }
    return newArr[newArr.length-1]}var arr = [8,8,8,8,6,2,7,3]//即使有重复,也是可以的console.log(getSecondBigNum(arr))

不足:引入新的数组,增加空间复杂度、可以第二次迭代直接与最大值比较,同时第一轮只为了求最大值也不需要排序,定义一个中间变量即可;


 目前总结到的最优化想法了~~~

既然排序,那就把其他排序再整合一下吧~

  • 快速排序

思路: 

- 随机选择数组中的一个数 A,以这个数为基准 

- 其他数字跟这个数进行比较,比这个数小的放在其左边,大的放到其右边

 - 经过一次循环之后,A 左边为小于 A 的,右边为大于 A 的

 - 这时候将左边和右边的数再递归上面的过程;

代码如下:(我们不考虑网上说的阮一峰老师的快排如何如何、我们只是说一种算法而已)


  • 选择排序

在时间复杂度上表现最稳定的排序算法之一,因为无论什么数据进去都是O(n²)的时间复杂度。。。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。


  • 插入排序

插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入


其实这些算法都挺有意思的,每次写的时候其实容易忘记,特别是三种方法的循环下标啥的,我总记不住,每次就举出一个简短的数据进行分析一下吧~~~网上还有很多种排序算法,什么希尔排序、归并排序、堆排序等等,再次就不一一介绍了~~