前端高频算法

news2024/11/25 14:35:56

分析算法排序:

  • 时间复杂度: 一个算法执行所耗费的时间。

  • 空间复杂度: 运行完一个程序所需内存的大小。

  • 执行效率内存消耗稳定性 三方面入手。

 1. 排序

1.1 冒泡排序

冒泡的过程只涉及相邻数据的交换操作,所以它的空间复杂度为 O(1)。

为了保证冒泡排序算法的稳定性,当有相邻的两个元素大小相等的时候,我们不做交换,相同大小的数据在排序前后不会改变顺序。 所以冒泡排序是稳定排序算法。

最佳情况:T(n) = O(n),当数据已经是正序时。

最差情况:T(n) = O(n(2)),当数据是反序时。

平均情况:T(n) = O(n(2))。

  bubbleSort = (arr) => {
    if (arr.length <= 1) return arr;
    for (let i = 0; i < arr.length - 1; i++) {
      let hasChange = false;
      for (let j = 0; j < arr.length - 1 - i; j++) {
        if (arr[j] > arr[j + 1]) {
          const temp = arr[j];
          arr[j] = arr[j + 1];
          arr[j + 1] = temp;
          hasChange = true;
        }
      }
      if (!hasChange) return;
    }
    console.log('arr', arr)
    return arr;
  }

const arr = [7, 8, 4, 5, 6, 3, 2, 1];
bubbleSort(arr);
1.2  插入排序

插入排序算法的运行并不需要额外的存储空间,所以空间复杂度是 O(1)。

在插入排序中,对于值相同的元素,我们可以选择将后面出现的元素,插入到前面出现元素的后面,这样就可以保持原有的前后顺序不变,所以插入排序是稳定的排序算法。

最佳情况:T(n) = O(n),当数据已经是正序时。

最差情况:T(n) = O(n(2)),当数据是反序时。

平均情况:T(n) = O(n(2))。

步骤

  • 从第一个元素开始,该元素可以认为已经被排序;

  • 取出下一个元素,在已经排序的元素序列中从后向前扫描;

  • 如果该元素(已排序)大于新元素,将该元素移到下一位置;

  • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;

  • 将新元素插入到该位置后;

  • 重复步骤 2 ~ 5。

  insertSort = (arr) => {
    if (arr.length <= 1) return arr;
    let preIndex, current;

    for (let i = 1; i < arr.length; i++) {
      preIndex = i - 1;
      current = arr[i];
      while (preIndex >= 0 && arr[preIndex] > current) {
        arr[preIndex + 1] = arr[preIndex];
        preIndex--;
      }

      if (preIndex + 1 !== i) {
        arr[preIndex + 1] = current;
      }
    }
    console.log('arr', arr)
    return arr;
  }
优化插入排序:折半插入
  • 取 0 ~ i-1 的中间点 ( m = (i-1) >> 1 ),array[i] 与 array[m] 进行比较,若 array[i] < array[m],则说明待插入的元素 array[i] 应该处于数组的 0 ~ m 索引之间;反之,则说明它应该处于数组的 m ~ i-1 索引之间。

  • 重复步骤 1,每次缩小一半的查找范围,直至找到插入的位置。

  • 将数组中插入位置之后的元素全部后移一位。

  • 在指定位置插入第 i 个元素。

// 折半插入排序
const binaryInsertionSort = array => {
        const len = array.length;
        if (len <= 1) return;

        let current, i, j, low, high, m;
        for (i = 1; i < len; i++) {
                low = 0;
                high = i - 1;
                current = array[i];

                while (low <= high) {
                        //步骤 1 & 2 : 折半查找
// 注: x>>1 是位运算中的右移运算, 表示右移一位, 等同于 x 除以 2 再取整, 
// 即 x>>1 == Math.floor(x/2) .
                        m = (low + high) >> 1; 
                        if (array[i] >= array[m]) {
                                //值相同时, 切换到高半区,保证稳定性
                                low = m + 1; //插入点在高半区
                        } else {
                                high = m - 1; //插入点在低半区
                        }
                }
                for (j = i; j > low; j--) {
                        //步骤 3: 插入位置之后的元素全部后移一位
                        array[j] = array[j - 1];
                        console.log('array2 :', JSON.parse(JSON.stringify(array)));
                }
                array[low] = current; //步骤 4: 插入该元素
        }
        console.log('array2 :', JSON.parse(JSON.stringify(array)));
        return array;
};
 1.3 选择排序

选择排序空间复杂度为 O(1)

选择排序每次都要找剩余未排序元素中的最小值,并和前面的元素交换位置,这样破坏了稳定性。所以,选择排序是一种不稳定的排序算法。

最佳/最差/平均情况:T(n) = O(n(2))。 

步骤

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

  3. 重复第二步,直到所有元素均排序完毕。

const selectionSort = array => {
        const len = array.length;
        let minIndex, temp;
        for (let i = 0; i < len - 1; i++) {
                minIndex = i;
                for (let j = i + 1; j < len; j++) {
                        if (array[j] < array[minIndex]) {
                                // 寻找最小的数
                                minIndex = j; // 将最小数的索引保存
                        }
                }
                temp = array[i];
                array[i] = array[minIndex];
                array[minIndex] = temp;
                console.log('array: ', array);
        }
        return array;
};
1.4  快速排序

因为 partition() 函数进行分区时,不需要很多额外的内存空间,所以快排是原地排序算法。

和选择排序相似,快速排序每次交换的元素都有可能不是相邻的,因此它有可能打破原来值为相同的元素之间的顺序。因此,快速排序并不稳定

最佳情况:T(n) = O(n log n)。

最差情况:T(n) = O(n(2))。

平均情况:T(n) = O(n log n)。

步骤

  • 先找到一个基准点(一般指数组的中部),然后数组被该基准点分为两部分,依次与该基准点数据比较,如果比它小,放左边;反之,放右边。

  • 左右分别用一个空数组去存储比较后的数据。

  • 最后递归执行上述操作,直到数组长度 <= 1;

特点:快速,常用。

缺点:需要另外声明两个数组,浪费了内存空间资源。

const quickSort1 = arr => {
        if (arr.length <= 1) {
                return arr;
        }
        //取基准点
        const midIndex = Math.floor(arr.length / 2);
        //取基准点的值,splice(index,1) 则返回的是含有被删除的元素的数组。
        const valArr = arr.splice(midIndex, 1);
        const midIndexVal = valArr[0];
        const left = []; //存放比基准点小的数组
        const right = []; //存放比基准点大的数组
        // 遍历数组,进行判断分配
        // 递归动态数组不要用len=arr.length替换arr.length
        for (let i = 0; i < arr.length; i++) { 
                if (arr[i] < midIndexVal) {
                        left.push(arr[i]); //比基准点小的放在左边数组
                } else {
                        right.push(arr[i]); //比基准点大的放在右边数组
                }
        }
        //递归执行以上操作,对左右两个数组进行操作,直到数组长度为 <= 1
        return quickSort1(left).concat(midIndexVal, quickSort1(right));
};
const array2 = [5, 4, 3, 2, 1];
console.log('quickSort1 ', quickSort1(array2));
// quickSort1: [1, 2, 3, 4, 5]
1.5 希尔排序

空间复杂度为 O(1)

希尔排序不稳定

最佳情况:T(n) = O(n log n)。

最差情况:T(n) = O(n log(2) n)。

平均情况:T(n) = O(n log(2) n)。

const shellSort = arr => {
        let len = arr.length,
                temp,
                gap = 1;
        console.time('希尔排序耗时');
        while (gap < len / 3) {
                //动态定义间隔序列
                gap = gap * 3 + 1;
        }
        for (gap; gap > 0; gap = Math.floor(gap / 3)) {
                for (let i = gap; i < len; i++) {
                        temp = arr[i];
                        let j = i - gap;
                        for (; j >= 0 && arr[j] > temp; j -= gap) {
                                arr[j + gap] = arr[j];
                        }
                        arr[j + gap] = temp;
                        console.log('arr  :', arr);
                }
        }
        console.timeEnd('希尔排序耗时');
        return arr;
};
2. 动态规划 
2.1 斐波拉契数列

0,1,1,2,3,5,8,13,21,34,55,......

function fibo (n) {
    if (n <= 0)  return 0;
    if (n === 1) return 1;
    return fibo(n - 1) + fibo(n - 2);
}

优化之后


function fibo (n) {
    if (n <= 0) return 0;
    if (n <= 1) return 1;
    var res, a = 0, b = 1;
    for (var i = 2; i <= n; i++) {
        res = a + b;
        a = b;
        b = res;
    }
    return res;
}
2.2  寻找最长公共字串
function maxSubString (str1, str2) {
    if (!str1 || !str2) return '';
    var len1 = str1.length,
        len2 = str2.length;
    var maxSubStr = '';
    for (var i = 0; i < len1; i++) {
        for (var j = 0; j < len2; j++) {
            var tempStr = '',
                k = 0;
            while ((i + k < len1) && (j + k < len2) && (str1[i + k] === str2[j + k])) {
                tempStr += str1[i + k];
                k++;
            }
            if (tempStr.length >  maxSubStr.length) {
                maxSubStr = tempStr;
            }
        }
    }
    return maxSubStr;
}
2.3  背包问题 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Deep learning Part Five RNN--24.4.29

接着上期&#xff0c;CBOW模型无法解决文章内容过长的单词预测的&#xff0c;那该如何解决呢&#xff1f; 除此之外&#xff0c;根据图中5-5的左图所示&#xff0c;在CBOW模型的中间层求单词向量的和&#xff0c;这时就会出现另一个问题的&#xff0c;那就是上下文的单词的顺序…

【JVM】class文件格式,JVM加载class文件流程,JVM运行时内存区域,对象分配内存流程

这篇文章本来只是想讲一下class文件格式&#xff0c;讲着讲着越讲越多。JVM这一块吧&#xff0c;知识比较散比较多&#xff0c;如果深研究下去如死扣《深入理解Java虚拟机》&#xff0c;这本书很深很细&#xff0c;全记住是不可能的&#xff0c;其实也没必要。趁这个机会直接把…

附录6-4 黑马优购项目-分类和购物车

目录 1 分类 1.1 接口 1.2 窗口限制 1.3 选中状态样式判断 1.4 点击左侧时右侧会到顶点 1.5 源码 2 购物车 2.1 store 2.2 tabBar徽标 2.3 滑动删除 2.4 结算 2.4.1 结算前登录 2.4.2 结算功能 2.5 触发组件事件 2.6 源码 1 分类 分类最上部是…

Flutter笔记:谈Material状态属性-为什么FlatButton等旧版按钮就废弃了

Flutter笔记 谈Material状态属性-为什么FlatButton等旧版按钮就废弃了 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this artic…

免安装SQL管理工具HeidiSQL建库如何选Collation字符校对

免安装SQL管理工具HeidiSQL 文章目录 免安装SQL管理工具HeidiSQL一、安装二、建库因此&#xff0c;通常我们选择&#xff1a; 一、安装 到官方网址&#xff1a;https://www.heidisql.com/ 下载后按不同版本安装或解压&#xff0c;运行目录中的heidisql应用程序。 该工具可以对…

「生存即赚」链接现实与游戏,打造3T平台生态

当前&#xff0c;在线角色扮演游戏&#xff08;RPG&#xff09;在区块链游戏市场中正迅速崛起&#xff0c;成为新宠。随着区块链技术的不断进步&#xff0c;众多游戏开发者纷纷将其游戏项目引入区块链领域&#xff0c;以利用这一新兴技术实现商业价值的最大化。在这一趋势中&am…

加州大学欧文分校英语中级语法专项课程02:Adjectives and Adjective Clauses 学习笔记

Adjectives and Adjective Clauses course certificate 本文是 https://www.coursera.org/learn/adjective-clauses 这门课的学习笔记。 文章目录 Adjectives and Adjective ClausesWeek 01: Adjectives and Adjective PhrasesLearning Objectives Adjectives Introduction Le…

基于Java的智慧社团综合管理系统的设计与实现(论文+源码)_kaic

摘 要 随着校园文化的不断丰富&#xff0c;大学里各种社团越来越多&#xff0c;社团活动也越来越频繁&#xff0c;社员也越来越多&#xff0c;而且大学生退社、入社比较频繁&#xff0c;社团管理就显得非常繁琐而又复杂,如果采用人工管理,对管理员来说将是一件很头疼的事情。设…

5个本地流畅运行大模型的免费工具

大家好&#xff0c;随着大型语言模型&#xff08;LLM&#xff09;驱动的聊天机器人逐渐普及&#xff0c;给人们的工作和生活带来了前所未有的便利。然而&#xff0c;这种便捷性背后潜藏着个人隐私信息被泄露的风险&#xff0c;例如AI公司会收集聊天记录和元数据来优化模型&…

【Vulhub靶场】Nginx 漏洞复现

Nginx 漏洞复现 一、Nginx 文件名逻辑漏洞&#xff08;CVE-2013-4547&#xff09;1、影响版本2、漏洞原理3、漏洞复现 二、Nginx 解析漏洞1、版本信息&#xff1a;2、漏洞详情3、漏洞复现 一、Nginx 文件名逻辑漏洞&#xff08;CVE-2013-4547&#xff09; 1、影响版本 Nginx …

mysql 数据转excel文件

mysql 数据转excel文件 缘由 为售后拉取数据&#xff0c;用navicat太墨迹了&#xff0c;用python写一个main方法跑一下&#xff1b; 1.抽取共同方法&#xff0c;封装成传入mysql&#xff0c;直接下载成excel&#xff1b; 2.写入所有sql语句&#xff0c;传入参数&#xff1b; 代…

2024-05-02 商业分析-杭州小万科技-商业模式分析

摘要: 对杭州小万科技的商业模式进行分析,以对其做出客观的评估。 杭州小万科技的资料: 杭州小万科技有限公司 - 企知道 (qizhidao.com) 杭州小万科技有限公司网站备案查询 - 天眼查 (tianyancha.com) 杭州小万科技有限公司 - 爱企查 (baidu.com) ​ 2023年年报:

Android手写自己的路由SDK

实现自己的路由框架 ​ 在较大型的Android app中常会用到组件化技术&#xff0c;针对不同的业务/基础功能对模块进行划分&#xff0c;从上到下为壳工程、业务模块、基础模块。其中业务模块依赖基础模块&#xff0c;壳工程依赖业务模块。同级的横向模块&#xff08;比如多个业务…

BeanFactory 源码浅析

BeanFactory 功能介绍 BeanFactory 是核心容器&#xff0c;负责管理 Bean 对象 BeanFactory 接口的功能只有一个 getBean() 方法BeanFactory 的实现类&#xff08;DefaultListableBeanFactory&#xff09;包含&#xff1a;控制反转、基本的依赖注入、Bean 生命周期的各种功能…

【Python】函数设计

1.联系函数的设计 2.找质数 3.找因子 4.判断水仙花数 5.斐波拉契数列递归调用&#xff0c;并用数组存储已计算过的数&#xff0c;减少重复计算 1、计算利息和本息 编写两个函数分别按单利和复利计算利息,根据本金、年利率、存款年限得到本息和和利息。调用这两个函数计算1…

【算法刷题日志】吸氧羊的StarryCoding之旅 - 贡献法计算

题目链接&#xff1a;https://www.starrycoding.com/problem/3 题目描述 吸氧羊终于注册了一个StarryCoding账号&#xff01;&#xff08;她很开心&#xff09; 但是吸氧羊忘记了它的密码&#xff0c;她想起你是计算机大师&#xff0c;于是就来请教你。 她虽然不记得密码了…

java版数据结构:深入理解栈和队列:数据结构与应用(vector,stack,queue)

目录 前言 动态数组类&#xff08;vector&#xff09; 特点&#xff1a; 应用&#xff1a; 栈&#xff08;Stack&#xff09; 栈的基础概念&#xff1a; 栈的常用方法&#xff1a; 模拟栈操作&#xff1a; 队列&#xff08;Queue&#xff09; 队列的基础概念 队列的常…

golang学习笔记(协程的基础知识)

golang的协程 协程是一种轻量级的线程&#xff0c;它可以实现并发执行的并行操作。协程是Go语言中的一个核心特性&#xff0c;它使得程序能够以并发的方式运行&#xff0c;并且非常高效。与传统的线程相比&#xff0c;协程的创建和销毁成本非常低&#xff0c;可以方便地启动大…

三维坐标点按剖面分类

一、写在前面 ①配套文件&#xff1a;根据剖面对三维坐标点&#xff08;X,Y,Z&#xff09;分类资源-CSDN文库 ②脱敏处理&#xff1a;蚀变数据已采用随机数生成覆盖 ③剖面坐标按顺序排列在“剖面坐标点.xlsx”文件中 二、3点确定空间中平面方程 原理&#xff1a; 设3点A&…

C++深度解析教程笔记2

C深度解析教程笔记2 第3课 - 进化后的 const 分析实验-C与C的const区别实验-C与C的const区别&const作用域 第4课 - 布尔类型和引用小结 本文学习自狄泰软件学院 唐佐林老师的 C深度解析教程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 第3课 - 进化后…