精华内容
下载资源
问答
  • 常见的算法问题

    2021-05-03 15:21:24
    常见的算法题java描述单链表的反转合并两个有序链表斐波那契数列问题给定一个数组arr,返回子数组的最大累加和给定一个数组arr、或者字符串,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。...

    单链表的反转

    递归方式:

    public Node preNode(Node head) {
            if(head == null || head.next == null)
                return head;
            Node preNode = preNode(head.next);
            head.next.next = head;
            head.next = null;
            return preNode;
        }
    

    合并两个有序链表

    public static Node mergeNode(Node node, Node node2) {
            Node head = new Node(-1);
            Node current = head;
            Node currentNode1 = node;
            Node currentNode2 = node2;
            while (currentNode1 != null && currentNode2 != null) {//注意此处是针对两个链表同等长度的情况,如果长度不同还要分开处理
                if (currentNode1.num <= currentNode2.num) {
                    current.next = currentNode1;
                    currentNode1 = currentNode1.next;
                } else {
                    current.next = currentNode2;
                    currentNode2 = currentNode2.next;
                }
                current = current.next;
            }
            return head.next;
        }
    

    斐波那契数列问题

    1、生兔子:有一对兔子,从出生后第四个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子。假如兔子都不死,计算第十个月兔子的总数?

        public static int f(int n) {
            if (n == 1 || n == 2 || n == 3) {
                return 1;
            }
            return f(n - 1) + f(n - 3);
        }
    

    2、跳台阶问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

        public static int jumpFloor(int n) {
            if (n <= 0)
                return 0;
            if (n <= 2)
                return n;
            return jumpFloor(n - 1) + jumpFloor(n - 2);
        }
    

    给定一个数组arr,返回子数组的最大累加和

        private static int maxSum(int[] array) {
            if (array == null || array.length == 0)
                return 0;
            int max = Integer.MIN_VALUE;
            int current = 0;
            for (int i = 0; i < array.length; i++) {
                current = current + array[i];
                max = Math.max(current, max);
                current = current < 0 ? 0 : current;
            }
            return max;
        }
    

    给定一个数组arr、或者字符串,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。

        public static int maxLength(String s) {
            Set<Character> set = new HashSet<>();
            int left = 0;
            int right = 0;
            int maxLength = 0;
            int len = s.length();
            while (left < len && right < len) {
                if (!set.contains(s.charAt(right))) {
                    set.add(s.charAt(right));
                    maxLength = Math.max(maxLength, right - left + 1);
                    right++;
                } else {
                    set.remove(s.charAt(left));
                    left++;
                }
            }
            return maxLength;
        }
    

    改进版: 东西理解了之后发现就能创新

    //最长无重复字符串
        public static int maxLength(String s) {
            int left = 0;
            int right = 0;
            int len = s.length();
            int maxLength = Integer.MIN_VALUE;
            Set<Character> set = new HashSet<>();
            while (left < len && right < len) {
                System.out.println("left = "+left+"; right = " + right);
                if (!set.contains(s.charAt(right))) {
                    set.add(s.charAt(right));
                    maxLength = Math.max(maxLength, right - left + 1);
                    right++;
                } else {
                    set.clear();//原来是left ++ 一个一个删除,这回直接删除,比原来的节省时间
                    left = right;
    //                set.remove(s.charAt(left));
    //                left++;
                }
            }
            return maxLength;
        }
    

    给出一个整数数组,请在数组中找出两个加起来等于目标值的数,

        public static int[] sum(int[] data, int target) {
            int[] result = new int[2];
            Map<Integer, Integer> map = new HashMap<>();
            for(int i =0;i<data.length;i++) {
                int value = target - data[i];
                if(map.containsKey(value)) {
                    result[0] = i;
                    result[1] = map.get(value);
                    map.put(data[i], i);
                }
            }
            return result;
        }
    

    数组a中只有一个数出现一次,其他数都出现了2次,找出这个数字

        public static int find1From2(int[] a){
            int len = a.length, res = 0;
            for(int i = 0; i < len; i++){
                res = res ^ a[i];
            }
            return res;
        }
    
    展开全文
  • 一、堆排序简介1. 理论如果给定输入列表A[1..n],其中n=len(A),则堆排序算法需要先构建一个最大堆,即最大...其次,由于新根节点可能使得当前完全二叉树违背堆序性质,因此可以采用元素交换的方式使其重新满足堆...

    0a9b635d75d1a57b79f548bdd087d67e.png

    一、堆排序简介

    1. 理论

    如果给定输入列表A[1..n],其中n=len(A),则堆排序算法需要先构建一个最大堆,即最大元素总是位于根节点处,且所有子节点不大于其父节点。由于最大元素位于根节点A[1]处,因此我们可以通过如下步骤对A进行排序:
    • 首先,将根节点和A[n]进行交换,则最大值的位置确定;
    • 其次,由于新的根节点可能使得当前完全二叉树违背堆序性质,因此可以采用元素交换的方式使其重新满足堆序性质,需要注意的是,此时元素交换时无需再考虑元素A[n]
    • 然后,将新的根节点和A[n-1]进行交换,则次大值的位置确定;
    • 再次,由于新的根节点可能使得当前完全二叉树违背堆序性质,再次采用元素交换的方式使其重新满足堆序性质,需要注意的是,此时元素交换时无需再考虑元素A[n]A[n-1]
    • 最后,重复上述过程,直到A[1..n]按照非递减顺序排列。

    2. 图解

    2.1 建最大堆

    实际上,给定一个列表,建一个最大堆的流程和建一个最小堆的流程基本一致,具体地,针对给定的10个元素列表,建堆步骤如下:
    • 首先,同建最小堆一样,如图(a)所示,自底向上,先确保以位置5为根节点的完全二叉树是一个二叉堆,此时满足最大堆的堆序性质,不涉及元素交换;
    • 其次,确保以位置4为根节点的完全二叉树是一个二叉堆,此时违背了最大堆的堆序性质,需对位置4和位置8的元素进行交换,如结果如图( c ) 所示;
    • 紧接着,依次确保以位置3,2,1处为根节点的完全二叉树是一个二叉堆,最终建堆结果如图( f )所示。

    0147b4061522ddc283d83e618b658491.png

    2.2 用最大堆排序

    下面是利用上述创建的最大堆进行排序的过程,具体地:

    • 首先,将根节点元素16和最底层最右侧元素1交换,然后通过元素交换使得不包括16在内的其他节点均满足堆序性质,结果如图( b )所示;
    • 然后,将根节点元素14和最底层最右侧元素1交换,然后通过元素交换使得不包括16和14在内的其他节点均满足堆序性质,结果如图( c ) 所示;
    • 重复上述过程,直到所有元素排好序,如图( j )所示。

    770b948ca8cf1f006af6bd9e6112585f.png

    二、堆排序实现

    由于堆一定是一个二叉树,而二叉树的实现可以是基于链式结构,也可以基于数组结构,为降低实现难度,且避免使用链式结构导致额外的内存开销(如一个节点保存其父、子节点引用所需的变量),这里使用基于数组结构来描述二叉树。
    def __down_heap(arr, num, j):    """    通过元素交换,确保列表arr[0:num]中,元素arr[j]及其子孙节点满足堆序性质    :param arr: 列表形式给出的待排序列    :param num: 列表索引上限    :param j: 列表元素的索引    :return: None    """    left = 2 * j + 1  # 元素arr[j]左子节点的索引    right = 2 * j + 2  # 元素arr[j]右子节点的索引    if left < num:  # 判断arr[j]是否有左子节点        large_child = left        if right < num:  # 判断arr[j]是否有右子节点            if arr[right] > arr[left]:                large_child = right        if arr[large_child] > arr[j]:  # 确保最终建成最大堆            arr[large_child], arr[j] = arr[j], arr[large_child]  # 交换两个节点处的值使满足堆序性质            __down_heap(arr, num, large_child)def heapify(arr):    """将列表形式给出的元素视为完全二叉树,对其进行建堆"""    for j in range((len(arr) - 1) // 2, -1, -1):  # 建堆        __down_heap(arr, len(arr), j)def heap_sort(arr):    """堆排序"""    heapify(arr)  # 构建最大堆    # 依次将最大值,次大值...最小值从右往左排好    for i in range(len(arr) - 1, 0, -1):        arr[i], arr[0] = arr[0], arr[i]  # 每一次迭代,将当前堆中最大元素排好序        __down_heap(arr, i, 0)  # 每迭代一次后元素arr[i]已排好序,仅需确保前i个元素满足堆序性质if __name__ == '__main__':    arr = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]    heap_sort(arr)    print(arr)

    三、堆排序复杂度

    1. 时间复杂度

    堆排序的时间复杂度分为两个部分:

    • 一部分是调用heapify函数的建最大堆所需的时间开销,由之前的理论分析可知为O ( n ) ;

    • 另一部分是循环调用__down_heap方法确保未排序的完全二叉树为最大堆的时间开销,可按照如下计算:

    l o g ( n − 1 ) + l o g ( n − 2 ) + ⋅ ⋅ ⋅ + l o g ( 1 ) = l o g ( ( n − 1 ) ! ) log(n-1)+log(n-2)+\cdot\cdot\cdot+log(1)=log((n-1)!)log(n1)+log(n2)++log(1)=log((n1)!)

    而:

    l o g ( ( n − 1 ) ! ) < l o g ( n ! ) < n l o g ( n ) log((n-1)!)

    最后忽略低阶项O ( n ) ,故最坏时间复杂度为n l o g ( n )。

    2. 空间复杂度

    由上述堆排序的实现代码可以看出,在堆排序过程中,除了输入的待排序列和排序过程中使用的辅助变量外,没有额外的内存开销,因此这是典型的原地排序,故其最坏空间复杂度为Θ ( n ) \Theta{(n)}Θ(n)。

    声明:https://blog.csdn.net/weixin_37780776/article/details/111403021

    bb6ad532f03c846e7ef014fe4c111dfc.png

    展开全文
  • JS 常见算法的解析和代码实现

    千次阅读 2020-08-18 16:56:17
    JS 常见算法的解析和代码实现 一、欧几里得定理(辗转相除法) 1. 条件 求 A 和 B 最大公约数,A 和 B 都是大于等于 0 整数。 2. 应用场景 欧几里得定理,在数学上,用来计算两个非负整数最大公约数。 辗转...

    JS 常见算法的解析和代码实现

    一、欧几里得定理(辗转相除法)

    1. 条件

    AB 的最大公约数,AB 都是大于等于 0 的整数。

    2. 应用场景

    欧几里得定理,在数学上,用来计算两个非负整数的最大公约数。

    辗转相除法就是 JS 实现欧几里得定理的具体方式。

    3. 分析

    欧几里得定理: 两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。

    用代码描述:ab 相除余数如果为 0,最大公约数直接是 b,如果余数是个不为 0 的数 c,接着往下计算,b 如果能整除 c,代表 bc 的最大公约数是 cab 的最大公约数也就是 c

    4. 代码实现

    假设求 2000 和 132 的最大公约数,数学计算过程为:

    被除数      除数          余数
    2000       132          20
    132        20           12
    20         12           8
    12         8            4
    8          4            0
    
    所以 2000 和 132 的最大公约数是 4
    

    我们可以将这个运算过程转换成代码逻辑,有两个变量 ab,做除法运算求余数,余数为 0 时,除数就是最大公约数,余数不为 0 时,用上一次的除数除以上一次的余数,继续求余数,直到某次运算余数为 0,那么当次运算的除数就是 ab 的最大公约数。

    转换成代码:

    function getGYS(a, b) {
      let c = null;
      while(c !== 0) {
        c = a % b;
        if(c === 0) return b;
        a = b;
        b = c;
      }
    }
    console.log(getGYS(10, 8));
    

    …写出来感觉代码很少,但实际上比起传统方式,用欧几里得算法求最大公约数,代码执行效率很高,循环次数非常少。

    二、二分查找

    二分查找是一种非常高效的数据查找方式,无论在哪种语言中,出现的频率都很高。

    1. 条件

    二分查找算法要求被查找序列要按照某种规律依照顺序排列。

    2. 应用场景

    • 电话簿里面找到一个指定首字母的联系人列表;
    • 数据量较大的查找需求;

    3. 分析

    有一个数组:[{
      id: 3,
      name: '赵一'
    }, {
      id: 5,
      name: '钱二'
    }, {
      id: 6,
      name: '孙三'
    }, {
      id: 20,
      name: '李四'
    }, {
      id: 55,
      name: '周五'
    }, {
      id: 98,
      name: '吴六'
    }, {
      id: 120,
      name: '郑七'
    }, {
      id: 150,
      name: '王九'
    }, {
      id: 199,
      name: '冯八'
    }, {
      id: 230,
      name: '陈十'
    }, {
      id: 401,
      name: '魏零'
    }]
    
    查询目的:想要查询 id 为 230 的这条数据的 name 值
    
    二分查找的思路:
    1. 先找到一个中间键,id 为 98 的这条数据,然后与 230 做比较。
    2. 确定要查找的 230 这条数据在整个列表中的位置,属于 98 左侧,还是 98 右侧。
    3. 这样一次就过滤掉一半无用的数据。
    4. 当 230 确定 在 98 右侧,继续找到下一个中间键 id 为 199 的这条数据。
    5. 199 和 230 作比较,确定 230 的这条数据在 199 的左侧还是右侧。
    6. 又过滤掉一半无用的数据。
    7. 依次类推,最终确定 id 为 230 这条数据的位置,拿到它。
    
    这样的查找过程比循环查找方便多了。
    

    4. 代码实现

    通过上面的分析,我们可以确定这样的代码逻辑,是我们需要一个中间键,来做过滤条件,中间键确定之后,我们就能确定要查找的数据在序列中的范围,范围肯定需要最大值和最小值,所以我们需要两个坐标来保留每次确定的范围。

    简化一数组,我们可以这样分析逻辑
    数组: [3, 5, 6, 20, 55, 98, 120, 150, 199, 230, 401]
    要查找的目标数据: 120
    
    范围最小下标   范围最大下标    中间键下标(小数取整)     中间键       比较
    0            10            (10 + 0) / 2 : 5      98          98 < 120
    5 + 1 = 6    10            (10 + 6) / 2 : 8      199         199 > 120
    6            8 - 1 = 7     (6 + 7) / 2 : 6       120         120 === 120 return
    
    范围最小下标和范围最大下标要进行加一减一的运算,是因为,在上一次的运算中,当前数据已经被运算了
    没有必要进行二次运算。
    

    转换成代码:

    const list = [{
        id: 3,
        name: '赵一'
      }, {
        id: 5,
        name: '钱二'
      }, {
        id: 6,
        name: '孙三'
      }, {
        id: 20,
        name: '李四'
      }, {
        id: 55,
        name: '周五'
      }, {
        id: 98,
        name: '吴六'
      }, {
        id: 120,
        name: '郑七'
      }, {
        id: 150,
        name: '王九'
      }, {
        id: 199,
        name: '冯八'
      }, {
        id: 230,
        name: '陈十'
      }, {
        id: 401,
        name: '魏零'
      }];
    
    function getData(list, id) {
      let min = 0, max = list.length - 1;
      while(min <= max) {
        let i = parseInt((max + min) / 2);
        let res = list[i];
        if(res.id === id) return res;
        else if(res.id < id) min = i + 1; 
        else if(res.id > id) max = i + 1;
      }
      return null;
    }
    console.log(getData(arr, 230));
    

    三、冒泡排序

    1. 应用场景

    将一组数据按照升序或者降序排列,比如商品列表,按照价格、销量升序或者降序排列。

    2. 分析

    冒泡排序的原理:

    • 比较相邻的元素。如果第一个比第二个大(小),就交换这两个元素。
    • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    比如有一组数据:[5, 31, 9, 0, 22, 16, 45]
    如果希望他们升序排列
       比较 5, 31 后者大,不变
       比较 31, 9 交换位置
       比较 31, 0 交换位置
       ...
    这种相邻似的的比较第一轮只能确定最后一个位置的值,其他数据的顺序还是乱的,所以要比较很多轮,才能将这组数据正确排序
    

    3. 代码实现

    根据上面的分析,我们确定以下几点:

    • 两两比较元素,根据排序规则交换位置,每次交换的元素都是当前拿到的元素和其下一个元素
    • 一轮交换并不能完全的将数组中的数据正确排列,需要多轮交换
    • 从最后一个位置,依次向前推动,每轮交换都能确定一个位置上的数据
    原数组:[5, 31, 9, 0, 22]
    排序要求:降序排列
    排序规律:
    假设每次交换的递增位置变量为 i,每轮交换的递增变量为 j,那么冒泡排序的排序规律如下
    
    j   i   i + 1   值比较       是否交换      数组
    0   0   1       5 < 31      是           [31, 5, 9, 0, 22]
    0   1   2       5 < 9       是           [31, 9, 5, 0, 22]
    0   2   3       5 > 0       否           [31, 9, 5, 0, 22]
    0   3   4       0 < 22      是           [31, 9, 5, 22, 0]
    1   0   1       31 > 9      否           [31, 9, 5, 22, 0]
    1   1   2       9 > 5       否           [31, 9, 5, 22, 0]
    1   2   3       5 < 22      是           [31, 9, 22, 5, 0]
    1   4   4       5 > 0       否           [31, 9, 22, 5, 0]
    2   0   1       31 > 9      否           [31, 9, 22, 5, 0]
    2   1   2       9 < 22      是           [31, 22, 9, 5, 0]
    2   2   3       9 > 5       否           [31, 22, 9, 5, 0]
    ...
    

    转换成代码:

    const arr = [5, 31, 9, 0, 22, 16, 45];
    function sort(_arr) {
      for(let i = 0; i < _arr.length; i++) {
        for(let j = 0; j < _arr.length; j++) {
          if(_arr[j] < _arr[j + 1]) {
            const temp = _arr[j];
            _arr[j] = _arr[j + 1];
            _arr[j + 1] = temp;
          }
        }
      }
      return _arr;
    }
    console.log(sort([...arr]));
    

    但是这种写法不是最优写法, 因为每次外层循环结束后,最终都能在数组的最后一个位置上确定一个数据,所以随着外层循环的执行,每次内层循环可以少判断几个位置,所以外层循环越执行到后面,内层循环的循环次数越少。
    所以优化代码:

    const arr = [5, 31, 9, 0, 22, 16, 45];
    function sort(_arr) {
      for(let i = 0; i < _arr.length; i++) {
        for(let j = 0; j < _arr.length - i; j++) {
          if(_arr[j] < _arr[j + 1]) {
            const temp = _arr[j];
            _arr[j] = _arr[j + 1];
            _arr[j + 1] = temp;
          }
        }
      }
      return _arr;
    }
    console.log(sort([...arr]));
    

    四、选择排序

    1. 应用场景

    选择排序和冒泡排序经常被一起提起,都是用来做序列排序的,只是内部执行机制不同而已。

    但是很多人容易把冒泡排序和选择排序搞混,那就是还是对原理和机制了解不到位,只是记住了代码。

    2. 分析

    选择排序的执行原理:

    • 从待排序的序列中拿到第一个数,假设它是当前序列的最小的数
    • 然后依次对比序列中的其他数,如果该数比最小的数小,那就交换位置
    • 第一轮结束之后进行第二轮比较,第二轮是从第二个位置开始,找剩余的数中最小的数
    • 以此类推,直到全部待排序的数据元素的个数为零
    比如有一组数据:[2, 5, 0, 1, 7, 9, 8, 6, 3]
    如果升序排列,我们需要这个序列第一个位置的值最小,最后一个位置的值最大
    那第一轮排序假设位置为 0 的元素 2 最小,对比其他元素,发现 0 实际最小,交换
    那么 0 在整个序列中最小
    第二轮在未排序的序列中,假设位置为 1 的元素 5 最小,对比其他元素,发现 1 最小,交换位置
    一次类推
    

    3. 代码实现

    根据上面的分析,我们需要双层循环,外层循环控制每次在未排序的序列中找到一个最小的或者最大的数,内层循环控制当次寻找的两两对比。

    还需要一个最小或者最大下标的保留值,用来找到实际最小或者实际最大的数时做数据交换

    排序数组:[22, 51, 10, 43, 75, 90, 3]
    排序要求:升序排列
    假设每次在剩余数列里找到一个最小值的递增位置变量为 i,每次寻找最小下标交换位置的循环递增变量为 j
    在寻找最小下标过程中,保留当前交换过的所有数的最小下标为 minIndex,每次初始值为当前剩余未排序序列中的最小下标
    
    i  j  arr[j]  arr[minIndex]   比较        minIndex保留值    数组
    0  1  51      22              51 > 22     0                -
    0  2  10      22              10 < 22     2                -
    0  3  43      10              43 > 10     2                -
    0  4  75      10              75 > 10     2                -
    0  5  90      10              90 > 10     2                -
    0  6  3       3               3 < 10      6                -
                                                             [3, 51, 10, 43, 75, 90, 22]
    3 已经是所有数里的最小数,所以待排序的序列是数组中除 3 之外的数,minIndex 在第二循环时,假定值应为 1
    而且第二轮循环不需要比较 3
    
    i  j  arr[j]  arr[minIndex]   比较        minIndex保留值    数组
    1  2  10      51              10 < 51     2                -
    1  3  43      10              43 > 10     2                -
    1  4  75      10              75 > 10     2                -
    1  5  90      10              90 > 10     2                -
    1  6  22      10              22 > 10     2                -
                                                             [3, 10, 51, 43, 75, 90, 22]
    [3, 10, 22, 43, 75, 90, 51]                        
    i  j  arr[j]  arr[minIndex]   比较        minIndex保留值    数组
    2  3  43      51              43 < 51     3                -
    2  4  75      43              75 > 43     3                -
    2  5  90      43              90 > 43     3                -
    2  6  22      43              22 < 43     6                -
                                                             [3, 10, 22, 43, 75, 90, 51]  
    ...
    

    还原成代码:

    const arr = [5, 31, 9, 0, 22, 16, 45];
    function sort(_arr) {
      for(let i = 0; i < _arr.length; i++) {
        let minIndex = i;
        for(let j = i + 1; j < _arr.length; j++) {
          if(_arr[j] < _arr[minIndex]) minIndex = j;
        }
        const temp = _arr[i];
        _arr[i] = _arr[minIndex];
        _arr[minIndex] = temp;
      }
      return _arr;
    }
    console.log(sort([...arr]));
    

    五、指定数随机分成 N 份

    1. 条件

    有一个指定的数 M,将其随机分成指定的份额

    2. 应用场景

    微信红包算法。

    3. 分析

    假如要求把 M 分成非等额的 N 份,我们可以每次从 M 中拿出一个数,给 0 ~ n - 1 位置上的任一一个数,这样分 M 次即可。

    4. 代码实现

    转换成代码:

    const num = 100, copies = 7;
    let arr = new Array(copies).fill(0);
    for(let i = 0; i < num; i++) {
    	const index = parseInt(Math.randon() * copies);
    	arr[index]++;
    }
    

    5. 拓展

    如果要求变一下, 将 M 随机分成 N 份,要求每一份不能小于 x,且不能大于 y(逻辑条件:不存在 M 不够分或 M 分剩下的情况)。

    思路:不能小于 x,那每个位置上的初始值就是 x。不能大于 y,那在分的这个过程中,如果某个位置上的数大于 y,那么这个位置,就不能再添加新的数据。

    代码:

    let sum = 100, copies = 20;
    let min = 3, max = 6;
    const arr = new Array(copies).fill(min);
    while(sum !== 0) {
    	const index = parseInt(Math.random() * copies);
    	if(arr[index] < max) {
    		arr[index]++;
    		sum--;
    	}
    }
    

    扫码拉你进入前端技术交流群

    在这里插入图片描述

    展开全文
  • 算法描述:* 冒泡排序:最简单,也最慢,貌似长度小于7最优* 插入排序: 比冒泡快,比快速排序和希尔排序慢,较小数据有优势* 快速排序:这是一个非常快排序方式,V8sort方法就使用快速排序和插入排序...

    今天发现一篇文章讲“JavaScript版几种常见排序算法”,看着不错,推荐一下原文:http://www.w3cfuns.com/blog-5456021-5404137.html

    算法描述:

    * 冒泡排序:最简单,也最慢,貌似长度小于7最优
    * 插入排序: 比冒泡快,比快速排序和希尔排序慢,较小数据有优势
    * 快速排序:这是一个非常快的排序方式,V8的sort方法就使用快速排序和插入排序的结合
    * 希尔排序:在非chrome下数组长度小于1000,希尔排序比快速更快
    * 系统方法:在forfox下系统的这个方法非常快

     

      1 // ---------- 一些排序算法
      2 // js 利用sort进行排序
      3 systemSort: function(array) {
      4     return array.sort(function(a, b) {
      5         return a - b;
      6     });
      7 },
      8 // 冒泡排序
      9 bubbleSort: function(array) {
     10     var i = 0,
     11     len = array.length,
     12     j, d;
     13     for (; i < len; i++) {
     14         for (j = 0; j < len; j++) {
     15             if (array[i] < array[j]) {
     16                 d = array[j];
     17                 array[j] = array[i];
     18                 array[i] = d;
     19             }
     20         }
     21     }
     22     return array;
     23 },
     24 // 快速排序
     25 quickSort: function(array) {
     26     //var array = [8,4,6,2,7,9,3,5,74,5];
     27     //var array = [0,1,2,44,4,324,5,65,6,6,34,4,5,6,2,43,5,6,62,43,5,1,4,51,56,76,7,7,2,1,45,4,6,7];
     28     var i = 0;
     29     var j = array.length - 1;
     30     var Sort = function(i, j) {
     31 
     32         // 结束条件
     33         if (i == j) {
     34             return
     35         };
     36 
     37         var key = array[i];
     38         var stepi = i; // 记录开始位置
     39         var stepj = j; // 记录结束位置
     40         while (j > i) {
     41             // j <<-------------- 向前查找
     42             if (array[j] >= key) {
     43                 j--;
     44             } else {
     45                 array[i] = array[j]
     46                 //i++ ------------>>向后查找
     47                 while (j > ++i) {
     48                     if (array[i] > key) {
     49                         array[j] = array[i];
     50                         break;
     51                     }
     52                 }
     53             }
     54         }
     55 
     56         // 如果第一个取出的 key 是最小的数
     57         if (stepi == i) {
     58             Sort(++i, stepj);
     59             return;
     60         }
     61 
     62         // 最后一个空位留给 key
     63         array[i] = key;
     64 
     65         // 递归        Sort(stepi, i);
     66         Sort(j, stepj);
     67     }
     68 
     69     Sort(i, j);
     70 
     71     return array;
     72 },
     73 
     74 // 插入排序
     75 insertSort: function(array) {
     76 
     77     // http://baike.baidu.com/image/d57e99942da24e5dd21b7080
     78     // http://baike.baidu.com/view/396887.htm
     79     //var array = [0,1,2,44,4,324,5,65,6,6,34,4,5,6,2,43,5,6,62,43,5,1,4,51,56,76,7,7,2,1,45,4,6,7];
     80     var i = 1,
     81     j, step, key, len = array.length;
     82 
     83     for (; i < len; i++) {
     84 
     85         step = j = i;
     86         key = array[j];
     87 
     88         while (--j > -1) {
     89             if (array[j] > key) {
     90                 array[j + 1] = array[j];
     91             } else {
     92                 break;
     93             }
     94         }
     95 
     96         array[j + 1] = key;
     97     }
     98 
     99     return array;
    100 },
    101 
    102 // 希尔排序
    103 //Jun.array.shellSort(Jun.array.df(10000));
    104 shellSort: function(array) {
    105 
    106     // http://zh.wikipedia.org/zh/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
    107     // var array = [13,14,94,33,82,25,59,94,65,23,45,27,73,25,39,10];
    108     var stepArr = [1750, 701, 301, 132, 57, 23, 10, 4, 1]; // reverse() 在维基上看到这个最优的步长 较小数组
    109     //var stepArr = [1031612713, 217378076, 45806244, 9651787, 2034035, 428481, 90358, 19001, 4025, 836, 182, 34, 9, 1]//针对大数组的步长选择
    110     var i = 0;
    111     var stepArrLength = stepArr.length;
    112     var len = array.length;
    113     var len2 = parseInt(len / 2);
    114 
    115     for (; i < stepArrLength; i++) {
    116         if (stepArr[i] > len2) {
    117             continue;
    118         }
    119 
    120         stepSort(stepArr[i]);
    121     }
    122 
    123     // 排序一个步长
    124     function stepSort(step) {
    125 
    126         //console.log(step) 使用的步长统计
    127         var i = 0,
    128         j = 0,
    129         f, tem, key;
    130         var stepLen = len % step > 0 ? parseInt(len / step) + 1 : len / step;
    131 
    132         for (; i < step; i++) { // 依次循环列
    133             for (j = 1;
    134             /*j < stepLen && */
    135             step * j + i < len; j++) { //依次循环每列的每行
    136                 tem = f = step * j + i;
    137                 key = array[f];
    138 
    139                 while ((tem -= step) >= 0) { // 依次向上查找
    140                     if (array[tem] > key) {
    141                         array[tem + step] = array[tem];
    142                     } else {
    143                         break;
    144                     }
    145                 }
    146 
    147                 array[tem + step] = key;
    148 
    149             }
    150         }
    151 
    152     }
    153 
    154     return array;
    155 
    156 }

     

    转载于:https://www.cnblogs.com/summer_shao/p/4318545.html

    展开全文
  • 面试常见算法

    2016-04-28 11:27:50
    好东西-算法寻找最小k个数题目描述输入n个整数,输出其中最小k个。解法一:快排要求一个序列中最小k个数,按照惯有思维方式,则是先对这个序列从小到大排序,然后输出前面最小k个数。至于选取什么排序...
  • JS 常见算法的解析和代码实现一、欧几里得定理(辗转相除法)1. 条件求 A 和 B 最大公约数,A 和 B 都是大于等于 0 整数。2. 应用场景欧几里得定理,在数学上,用来计算两个非负整数最大公约数。辗转相除法...
  • 这篇文章并不去细说 Nginx 这类软件的具体配置,只是着重来了解几种常见的负载均衡算法的实现(本文使用Java描述)与应用。对于我们来讲,所了解的最基本的负载均衡算法包括了:随机、轮询、一致性Hash等几种方式,...
  • 常见算法

    千次阅读 2013-09-12 21:26:50
    一、维护O(1)时间查找最大元素栈 ...可以修改栈存储方式,push,pop操作,但是要保证O(1)时间复杂度,空间时间复杂 度无要求。   可以创建一个类,类里有两个栈,一个栈S维持正常push、po
  • 文章目录一、考点1、冒泡排序原理和实现1)原理2)实现冒泡排序最终...③ 一个算法具有五个特征2)时间复杂度和空间复杂度概念① 算法评定② 时间复杂度③ 时间复杂度计算方式④ 举例常见时间复杂度:常数阶、线...
  • JS 常见算法的解析和代码实现一、欧几里得定理(辗转相除法)1. 条件求 A 和 B 最大公约数,A 和 B 都是大于等于 0 整数。2. 应用场景欧几里得定理,在数学上,用来计算两个非负整数最大公约数。辗转相除法...
  • 常见算法之寻找K大数

    2017-12-13 20:13:04
    此篇博文主要是对面试过程中的算法题进行记录。 该题作为面试常见题型,同时拥有多种实现方式。 后续会对相关算法进行具体代码实现。 题目描述: 有很多个无序的数,怎么选出其中最大的若干个数?即,从n个数中...
  • 位数按照逆序方式存储,它们每个节点只存储单个数字。将两数相加返回一个新链表。你可以假设除了数字 0 之外,这两个数字都不会以零开头。示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)输出:7 -> ...
  • 单链表置逆是面试中常见的算法之一,很简单,想用最简洁最通俗易懂的方式描述下这个算法,希望大家在面试中思路清晰,半分钟秒杀它思路:以单链表有4个节点为例,1->2->3->4 反转就是取2,放到1前面;继续取3放到2...
  • 描述:我们从未排序列表中不断获取最小元素,将它放置到数组做左侧[0] 如果数组中下标为0元素本身就已经是最小元素话,name它自己与自己进行交换 为了变上述自己同自己交换问题,我们采取使用if判断...
  • 位数按照逆序方式存储,它们每个节点只存储单个数字。将两数相加返回一个新链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 示例: 输入:(2 -> 4 -> 3) (5 -> 6 -> 4) 输出:7 -...
  • 一、两个大数相加 ...5、两个数都是以字符串的方式提供。 输入描述 56723 82734123 输出描述 82790846 算法关键点 1、字符串转数组 2、字符串翻转 3、ASCII码加减处理 4、数字相加进位处理 public class Mai...
  • 目录6.6 priority_queue的常见用法详解...读入任务调度序列,输出n个任务适合一种调度方式。 输入 输入包含多组测试数据。 每组第一行输入一个整数n(n<100000),表示有n个任务。 接下来n行,每行第一个表示前...
  • 问题描述:凯撒密码是把字母表中每个字母用该字母后某个字母进行代替。凯撒密码通用加密算法是:C=E(P)=(P+k) mod 260凯撒密码通用解密算法是:P=D(C)=(P-k) mod 260基本要求:实现凯撒密码加密、解密算法...
  • 位数按照逆序方式存储,它们每个节点只存储单个数字。将两数相加返回一个新链表。你可以假设除了数字 0 之外,这两个数字都不会以零开头。示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)输出:7 -> ...
  • 算法算法的效率时间复杂度大O表示法常数阶线性阶对数阶平方阶常见时间复杂度比较 算法的定义是这样:解题方案准确而完善的描述,是一系列解决问题清晰指令。巴拉巴拉,虽然是一小句但还是不想看(题外话:...
  • 位数按照逆序方式存储,它们每个节点只存储单个数字。将两数相加返回一个新链表。你可以假设除了数字 0 之外,这两个数字都不会以零开头。示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)输出:7 -> ...
  • 常见算法题(包括华为机试题)

    千次阅读 2014-04-01 14:54:07
    一、维护O(1)时间查找最大元素栈 ...可以修改栈存储方式,push,pop操作,但是要保证O(1)时间复杂度,空间时间复杂 度无要求。 可以创建一个类,类里有两个栈,一个栈S维持正常push、pop
  • 常见的查找算法主要有顺序查找、二分查找、哈希表查找和二叉排序树查找。 在面试的时候,不管使用循环还是用递归,都需要掌握完整正确的二分查找代码。 哈希表和二叉排序树查找的重点在于考查对应的数据结构而不是...
  • 算法的时间复杂度

    2020-10-05 10:58:35
    文章目录时间复杂度常数阶线性阶平方阶实例分析常见的时间复杂度 时间复杂度 在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述算法的运行时间。这是一个代表算法输入值的...
  • 读入任务调度序列,输出n个任务适合一种调度方式。 输入 输入包含多组测试数据。 每组第一行输入一个整数n(n<100000),表示有n个任务。 接下来n行,每行第一个表示前序任务,括号中任务为若干个后序任务,...
  • 相似度算法

    2021-01-19 16:04:17
    这种算法在nlp领域比较常见,其他地方怎么用就仁者见仁啦~ 相似度算法 算法名称 简单描述 LCS 最长公共子序列 Hamming Distance 汉明距离 Cosine Similarity 余弦相似度算法...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 516
精华内容 206
关键字:

常见的算法描述方式