js算法学习

151 阅读6分钟

前言

时间过的很快,转眼学习算法有一个月,稍微有一些感觉了,对一些简单的题也能解出结果了,排序也不是只知道冒泡了,还知道了选择,插入,二分,基数排序。跟下来发现有些知识一点一点慢慢的了解下来还是很有意思的,遵寻一定的法则得到相应的结果,自己来说直观上是某些速度变快了,比如前后台数据交互的时候不再完全依赖后台的数据,自己组织自己想要的数形式时,可以更快。渐渐的体会到 程序=算法+数据结构 这一个感觉,某些时候一个好的算法和数据结构结合起来,某个功能的实现就是那easy 相反搭配不好的导致,前端工作者要花费时间,处理数据 然后还要处理现代web页面的复杂的交互,处理完还要处理交互后的数据在给到后端工作者我认为这样的前后交互方式费力的,前端工作者很多精力花在这些上面,而不是让精力聚焦在页面的交互与展示上,很多人说现在前端都是组件库,你前端不就是看着文档把人家写的组件拿来用不就好了,有什么难的,对,大多数情况下是说得不错,那你后台返数据的时候反的和人组件库一样的数据啊,人家组件文档的给的是数组,你偏偏返加一棵树的结构,让你改你说关联到好些表,这时前端不处理这个能用吗。然而项目的进度多数问题都是在前端这里,在没有达到tdd的开发中,出现就一种情况是正常的,领导问后端进度,后端就说接口已经写完了,前端人员呢联调一个接口,按文档去传参数,发现某些参数不是必参,不传接口,异常500 出错信息没有,前端人员部分展示和操作连接起来,发现少接口,这时后端人员又要加一个, 某些参数呢,串连业务操作时呢没有这个数据,后端人员呢又要在某个环节加一个。前端工作量能不增加吗。如果你觉得你经常遇到这样的情况,那么恭喜你,你如果不能很好处理这些问题项目又不能延期的话,一个项目跟下来,你正常下班的情形应该不多,话往回说,不遇到这些问题又怎么知道怎么支解决呢。有些人的能力并没有多强,但是人家遇到过知道怎么应对,所以人家就比你强,在算法上我觉得有这样的感觉,你如果只知道冒泡,你遇到有排序的需要时并且要自己实现的时候,你还会考虑到数据量怎么样,怎样速度更快,目前自己技能中那个技能最适合用在此处,我想这会打一个大大的问号。今天分享的算法和今天的前言一样有点杂。

罗马数转数字

描述

罗马数字包含以下七种字符: I, V, X, LCD 和 M

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即> 为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。 这个特殊的规则只适用于以下六种情况:

 R1 I 可以放在 V (5) 和 X (10) 的左边,来表示 49。

 R2 X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。

 R3 C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900

给定一个罗马数字,将其转换成整数。来源:力扣(LeetCode)链接

解题思路

  1. 先定义一map 用来对应七种字符串
  2. 根据对应字符可以转成对应数字
  3. 根椐前文R1, R2, R3 加入遇到”特殊“情况的处理

解:

    function romanToInit(s) {
        // 七种字符对值
        const romanMap = new Map([
          ['I', 1],
          ['V', 5],
          ['X', 10],
          ['L', 50],
          ['C', 100],
          ['D', 500],
          ['M', 1000]
        ])
        let count = 0;
        
        for(let i = 0; i < s.length; i++){
           // 处理对应”特殊“规则
           if(romanMap.get(s[i]) < romanMap.get(s[i+1])) {
               count -= romanMap.get(s[i]);
           } else {
               count += romanMap.get(s[i]);
           }
        }
        
        return count;
    }

返回倒数第k个节点的值

描述

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。 来源:力扣(LeetCode)链接

解题思路

  1. 设置两个指针一个标记为快一个标记为慢
  2. 让标记为快的指针移动k次
  3. 快慢指针同时移动直到快指针指向为空

解:

    function kthTolastTwo(head, k) {
        // 设置快慢指针
        let q = head; 
        let s = head;
        
        // 快指针移动k次
        for(let i = 0; i<k; i++) {
            q = q.next;
        }
        
        // 同时移动
        while(q) {
            q = q.next;
            s = s.next;
        }
        
        return s.val;
    }

是否是环型链表

描述

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 如果链表中存在环,则返回 true 。 否则,返回 false 。来源:力扣(LeetCode)链接

示例:

image.png

解题思路

  1. 扫描时判断副本是否存在如果不存在添加副本
  2. 一遍扫描完成后再次扫描如果副本存在说明环存在

解:

    function hasCycle(head) {
        let tmp = head;
        
        while(tmp) {
            if(tmp.flag) {
               // 如果副本存在说明有环存在
               return true;
            }else {
                // 扫描添加副本
                tmp.flag = true;
            }
        }
        
        return false;
    }

出现一次的数

描述

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。来源:力扣(LeetCode)链接

解题思路

  1. 扫描一遍,如果出现记录次数据,找到次数为1的数据

    function isOnece(arr) {
        let obj = {};
        
        arr.map(item => {
            if(obj[item]){
                obj[item] = 1;
            }else {
                obj[item]++;
            }
        })
        
        
       for(let s in obj){
           if(ojb[s] == 1) {
               return Number(s);
           }
       }
    }