算法小记

137 阅读4分钟

前置知识

1.数组
  • 1.fill(局限,不能填充引用数据类型) const arr = (new Array(7)).fill(1)
  • 2 for,forEach,map
2.栈和队列
前置知识
  • unshift ⽅法-添加元素到数组的头部
  • push ⽅法-添加元素到数组的尾部
  • splice 中删除任意位置元素的⽅法
    • arr.splice(1,1) //第⼀个⼊参是起始的索引值,第⼆个⼊参表示从起始索引开始需要删除的元素个数。
    • arr.splice(1,0,3) //在这个例⼦⾥,我们就指明了从 arr[1] 开始,删掉 0 个元素,并且在索引为1的地⽅ 新增了值为3的元素
  • shift ⽅法-删除数组头部的元素
  • pop ⽅法-删除数组尾部的元素
栈(Stack)⸺只⽤ pop 和 push 完成增删的“数组”(满足后进先出原则)
队列(Queue)⸺只⽤ push 和 shift 完成增删的“数组”(满足先进先出原则)
3.链表

在内存中可以是离散的。数组在内存中最为关键:⼀段连续的内存空间。

  • 链表的创建方式
function ListNode(val) { 
    this.val = val; 
    this.next = null; 
}
const node = new ListNode(1) 
node.next = new ListNode(2)
  • 链表元素的添加
const node = new ListNode(1) 
node.next = new ListNode(2)
// 如果⽬标结点本来不存在,那么记得⼿动创建 const node3 = new ListNode(3) // 把node3的 next 指针指向 node2(即 node1.next)
const node3 = new ListNode(3)
node3.next = node1.next
node1.next=node3
  • 链表元素的删除
    • 例删除node3

    删除的标准是:在链表的遍历过程中,⽆法再遍历到某个结点的存在。按照这 个标准,要想遍历不到 node3,我们直接让它的前驱结点 node1 的 next 指针跳过它 node1.next = node3.next

4.二叉树

必须满足一下条件:1.它可以没有根结点,作为⼀棵空树存在。 2.如果它不是空树,那么必须由根结点、左⼦树和右⼦树组成,且左右⼦树都是⼆叉树。

  • 遍历⽅式
    • 先序遍历
      • 根结点 -> 左⼦树 -> 右⼦树
    • 中序遍历
      • 左⼦树 -> 根结点 -> 右⼦树
    • 后序遍历
      • 左⼦树 -> 右⼦树 -> 根结点
  • 举例

image.png

先序遍历结果 image.png

中序遍历结果 image.png

后序遍历结果 image.png

常见算法
双指针

双指针法用在涉及求和、比大小类的数组题目里时,大前提往往是:该数组必须有序。否则双指针根本无法帮助我们缩小定位的范围,压根没有意义,但是极个别无序也可用。

什么时候你需要联想到对撞指针? 这⾥我给⼤家两个关键字⸺“有序”和“数组”。 没错,⻅到这两个关键字,⽴刻把双指针法调度进你的⼤脑内存。普通双指针⾛不通,⽴刻想对撞指针!

  • 对应leetcode的15题 26题
回文
  • 基本功能:反转字符串
//判断是否是会问字符串的通用方法
    // 反转字符串
    const reversedStr = str.split('').reverse().join('')
   
  • 同时,回文字符串还有另一个特性:如果从中间位置“劈开”,那么两边的两个子串在内容上是完全对称的。因此我们也可以结合对称性来做判断:
//判断是否是会问字符串的通用方法
function isPalindrome(str) {
    // 缓存字符串的长度
    const len = str.length
    // 遍历前半部分,判断和后半部分是否对称
    for(let i=0;i<len/2;i++) {
        if(str[i]!==str[len-i-1]) {
            return false
        }
    }
    return true
}

链表
  • 链表题目分为以下三类:
    • 链表的处理:合并、删除等(删除操作画个记号,重点中的重点!)
    • 链表的反转及其衍生题目
    • 链表成环问题及其衍生题目
  • 链表常规:合并、删除等
    • 合并:定义一个新链表,比较两个链表大小,指名新链表的指向 :leetcode 21题
    • 删除:删除首先想到更改删除节点的前一个节点的next指向,但是也要具体题目具体分析。
      • 常规:leetcode 83题
      • 新增一个新的节点:leetcode 82题
      • 直接访问删除节点:leetcode 237题
      • 环形:设置map数据格式辅助,记录已经访问过 leetcode 141题

很有用的小贴士:dummy 头结点,

它可以帮我们处理掉头结点为空的边界问题,帮助我们简化解题过程。因此涉及链表操作、尤其是涉及结点删除的题目(对前驱结点的存在性要求比较高),我都建议大家写代码的时候直接把 dummy 给用起来。 const dummy = new ListNode(null,head)

  • 链表中的快慢指针和多指针
    • 快慢指针:删除链表的倒数第 N 个结点 leetcode 21题

      • 1.求长度
      • 2.做减法,找定位。

      通过快指针先行一步、接着快慢指针一起前进这个操作,巧妙地把两个指针之间的差值保持在了“n”上(用空间换时间,本质上其实就是对关键信息进行提前记忆,这里咱们相当于用两个指针对差值实现了记忆),这样当快指针走到链表末尾(第 len 个)时,慢指针刚好就在 len - n 这个地方稳稳落地。

    • 多指针:leetcode 206题

    • 多指针(难度较大):局部反转一个链表 leetcode 92题