如何快速准备大厂秋招面试中的算法


首先分享一下个人经历,本人是2021届毕业生,普通本科非计算机专业历经春招毒打成功上岸某大厂,已入职。互联网大厂校招算法是必备的,基础的算法不过关笔试都过不了,我在校招之前在leetcode刷了100+算法题,整理了一些自己的笔记,分享给有需要的人。个人觉得数据结构以及算法学习还是挺重要,尤其像我这种非科班出生的程序员,内容不是很完善,大家也可以留言区补充。

数据结构

1、栈

1.1 栈的概述

栈(stack),它是一种受限的线性质,后进先出(LIFO)

  • 其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底

1.2 栈的常规操作

方法作用
push(e)添加一个新元素到栈顶
pop()移除栈顶元素,同时返回被移除的元素
peek()返回栈顶元素,不对栈做任何的修改
isEmpty()如果栈里没有任何元素就返回true,否则返回false
size()返回栈里的元素个数。这个方法和数组的length很类似
toString()将栈结构的内容以字符串形式返回

1.3 用js封装栈

function Stack(){
	this.stack = []
}
Stack.prototype.push=function(element) {
	this.stack.push(element)
}
Stack.prototype.pop=function(){
	return this.stack.pop()
}
Stack.prototype.size=function(){
	return this.stack.length
}
Stack.prototype.peek=function(){
	return this.stack[this.size()-1]
}
Stack.prototype.isEmpty=function() {
	return this.size === 0 ? true : false
}
Stack.prototype.toString=function(){
	return this.stack.join(' ')
}

1.4 栈的应用

有效的括号队列的最大值最小栈

2、队列

2.1 队列的概述

队列(queue),它是一种受限的线性质,先进先出(LIFO)

  • 其限制是仅允许在表的前端进行删除操作,在表的后端进行插入操作

2.2 队列的常规操作

方法作用
enqueue(e)向队列尾部添加一个或多个新的元素
dequeue()移除队列第一个元素,同时返回被移除的元素
front()返回队列第一个元素,不对队列任何的修改
isEmpty()如果队列里没有任何元素就返回true,否则返回false
size()返回队列里的元素个数。这个方法和数组的length很类似
toString()将队列的内容以字符串形式返回

2.3 用js封装队列

function Queue(){
    this.queue = []
}
Queue.prototype.enqueue = function(ele){
    this.queue.push(ele)
} 
Queue.prototype.dequeue = function(){
    return this.queue.shift()
} 
Queue.prototype.front = function(){
    return this.queue[this.size() -1]
} 
Queue.prototype.size = function(){
    return this.queue.length
} 
Queue.prototype.front = function(){
    return this.size === 0 
} 
Queue.prototype.toString = function(){
    return this.queue.join('') 
} 

2.4 队列的应用

设计循环队列设计双端队列最近请求次数

3、链表

3.1链表的概述

链表 [Linked List]:链表是由一组不必相连【不必相连:可以连续也可以不连续】的内存结构 【节点】,按特定的顺序链接在一起的抽象数据类型。

3.2 链表的常规操作

方法作用
append(ele)向链表尾部添加一个元素
insert(index,ele)向链表的特定位置插入一个新的项
get(index)获取对应位置的元素
indexOf(ele)返回元素在链表的第一个匹配元素的索引,如果没有则返回-1
update(index)修改某个位置的元素
removeAt(index)从链表的特定位置移除当前元素
remove(ele)从链表种移除该元素
isEmpty()如果链表没有任何元素,返回true,否则返回false
size()返回链表包含的元素个数。与数组的length属性类似
toString()由于链表使用了Node类,需要重写toString()方法,让其只输出元素的值

3.3 用js封装链表

function LinkedList (){
    //链表头
    this.head = null
    this.length = 0
}
 // 创建链表节点
function Node(data){
    this.data = data
    this.next = null
}
LinkedList.prototype.append = function(data){
    let newNode = new Node(data)
    if(this.length === 0){
        this.head = newNode
    }else{
        let currentNode = this.head
        while(currentNode.next){
            currentNode = currentNode.next
        }
        currentNode.next = newNode
    }
    this.length += 1
}
LinkedList.prototype.insert = function(index, data){
    let newNode = new Node(data)
    if(index < 0 || index > this.length) return false
    //插入的节点为第一个
    if(index === 0){
        newNode.next = this.head
        this.head = newNode
    }else{
        let currentNode = this.head,
        curIndex = 0,
        previous = null
        while(curIndex ++ <  index){
            previous = currentNode
            currentNode = currentNode.next
        }
        newNode.next = currentNode
        previous.next = newNode
    }
    this.length ++ 
    return true
}
LinkedList.prototype.get = function(index){
    if(index < 0 || index > this.length) return null
    let curNode = this.head,
        curIndex = 0 
    while(curIndex++ < index){
        curNode = curNode.next
    }
    return curNode.data
}
LinkedList.prototype.indexOf = function(item){
    let curNode = this.head,
        curIndex = 0
    while(curNode){
        curNode = curNode.next
        if(curNode && curNode.data == item){
            return curIndex
        }
    }
    return -1
}
LinkedList.prototype.update = function(index, item){
    if(index < 0 || index > this.length) return false
    let curNode = this.head,
        curIndex = 0
    while(curIndex++ < index){
        curNode = curNode.next
    }
    curNode.data = item
}
LinkedList.prototype.removeAt = function(index){
    if(index < 0 || index > this.length) return null
    if(index === 0){
        this.head = null
    }else{
        let curNode = this.head,
        previous = null,
        curIndex = 0

    while(curIndex++ < index){
        previous = curNode
        curNode = curNode.next
    }
    previous.next = curNode.next
    }
    this.length --
}
LinkedList.prototype.remove = function(data){
    let index = this.indexOf(data)
    this.removeAt(index)
}
LinkedList.prototype.isEmpty = function(){
    return this.length > 0 ?  true : false
}
LinkedList.prototype.toString = function() {
    let res = '',
    currentNode = this.head
    while(currentNode){
        res += currentNode.data
        currentNode = currentNode.next 
    }
    return res
}

3.4 链表的应用

两数相加合并k个升序链表旋转链表分离链表

4、集合

4.1 集合的概述

集合通常是由一组无序、不能重复的元素构成。不能通过下标进行访问

4.2 集合的常规操作

方法作用
add(value)向集合添加一个元素
remove(value)从集合移除一个元素
has(value)如果在集合中,返回true,否则返回false
clear()移除集合中的所有项
size()返回集合所包含元素的数量,与数组的length属性类似
values()返回一个包含集合所有值的数组

4.3 用js封装集合

function Set(){
    this.items = {}
}
Set.prototype.add = function(value){
    if(this.has(value)) return false
    this.items[value] = value
    return true
}
Set.prototype.has = function(value){
    return this.items.hasOwnProperty(value)
}
Set.prototype.remove = function(value){
    if(!this.has(value)) return false
    delete this.items[value]
    return true
}
Set.prototype.clear = function(){
    this.items = {}
}
Set.prototype.size = function(){
    return Object.keys(this.items).length
}
Set.prototype.values = function(){
    return Object.keys(this.items)
}

4.4 集合的应用

删除数组中重复的元素存在重复元素两个数组的交集

5、哈希表

5.1 哈希表的概述

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表

5.2 哈希表的常规操作

方法作用
hashFunc(str,size)将字符串或者数字哈希化
put(key,value)向哈希表添加或者更新一个元素
remove(key)从哈希表中移除一个元素
get(key)查询哈希表中的某个值
isEmpty()判断哈希表是否为空

5.3 用js封装哈希表

function HashTable(limit){
    this.storage = []
    this.count = 0
    this.limit = limit
}
// 哈希函数
HashTable.prototype.hashFunc = function(str, size){
    let hashCode = 0
    //霍纳算法
    for(let i=0;i< str.length;i++){
        hashCode = hashCode * 37 + str.charCodeAt(i)
    }
    // 取余 && 位运算
    let index = hashCode % size
    return index;
}
HashTable.prototype.put =function(key, value){
    let index = this.hashFunc(key, this.limit)
    if(!this.storage[index]){
        this.storage[index] = []
    }
    // 判断是否修改数据
    for (let i = 0;i < this.storage[index].length; i++){
        let tuple = this.storage[index][i]
        if(tuple[0] == key){
            tuple[1] = value
            return
        }
    }
    // 添加操作
    this.storage[index].push([key,value])
    this.count ++   
}
HashTable.prototype.get = function(key){
    // 1、根据key获取对应的index
    let index = this.hashFunc(key, this.limit)
    // 2、根据index获取对应的bucket
    let bucket = this.storage[index]
    // 3、线性查找值
    if(!bucket){
        return null
    }
    for(let i=0;i<bucket.length;i++){
        let tuple = bucket[i]
        if(tuple[0] === key){
            return tuple[1]
        }
    }
    // 4、如果都没找到,返回null
    return null
}
HashTable.prototype.remove = function(key){
    let index = this.hashFunc(key, this.limit),
        bucket = this.storage[index]
    if(!bucket){
        return null
    }
    for (let i = 0; i< bucket.length; i++) {
       let tuple = bucket[i];
       if(tuple[0] == key){
           bucket.splice(i,1)
           this.count --
           return tuple[1]
       }
    }
    return null
}
HashTable.prototype.isEmpty = function(){
    return this.count == 0
}

5.4 哈希表的应用

四数之和无重复数字最长字串最小覆盖字串字母异位词分组

6、二叉搜索树

6.1 二叉树的概述

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分 。

6.2 二叉树的常规操作

方法作用
insert(key)向树插入一个新的值
search(key)在树中查找一个键,如果节点存在,则返回true;如果不存在,则返回false
inOrderTraverse()通过中序遍历方式遍历所有节点
preOrderTraverse()通过先序遍历方式遍历所有节点
postOrderTraverse()通过后序遍历方式遍历所有节点
min()返回树中的最小的值
max()返回树中最大的值
remove(key)从树中移除某个值

6.3 用js封装二叉树

function BinarySearchTree(){
    this.root = null
}
function CreateNode(key){
    this.left = null
    this.right = null
    this.key = key
}
BinarySearchTree.prototype.insert = function(key){
    // 1.创建节点
    let node = new CreateNode(key)
    // 2.判断根节点是否有值
    if(this.root === null){
        this.root = node
    }else{
        insertNode(this.root,node)
    }
    function insertNode(root, node){
        if(node.key < root.key){
            if(!root.left){
                root.left = node
            }else{
                insertNode(root.left, node)
            }
        }else {
            if(!root.right){
                root.right = node
            }else {
                insertNode(root.right, node)
            }
        }
    }
}
BinarySearchTree.prototype.inOrderTraverse = function(node){
    if(!node) return
    console.log(node.key)
    this.inOrderTraverse(node.left)
    this.inOrderTraverse(node.right)
}
BinarySearchTree.prototype.midOrderTraverse = function(node){
    if(!node) return
    this.midOrderTraverse(node.left)
    console.log(node.key)
    this.midOrderTraverse(node.right)
}
BinarySearchTree.prototype.postOrderTraverse = function(node){
    if(!node) return
    this.postOrderTraverse(node.left)
    this.postOrderTraverse(node.right)
    console.log(node.key)

}
BinarySearchTree.prototype.max = function(){
    let node = this.root
    while(node !== null && node.right){
        node = node.right
    }
    return node.key
}
BinarySearchTree.prototype.min = function(){
    let node = this.root
    while(node !== null && node.left !== null){
        node = node.left
    }
    return node.key
}
BinarySearchTree.prototype.search = function(key){
    let node = this.root
    while(node !== null){
       if(key < node.key){
           node = node.left
       }else if(key > node.key){
           node = node.right
       }else{
           return true
       }
    }
    return false
}
BinarySearchTree.prototype.remove = function(key){
    let current = this.root,
        parent  = null,
        isLeftChild = true;
    // 寻找该节点
    while(current.key !== key){
       parent = current
       if(key < current.key){
           isLeftChild = true
           current = current.left
       }else{
           isLeftChild = false
           current = current.right
       }
    //    遍历完没找到
       if(current === null) return false
    }
    // 删除节点是叶子节点(没有子节点)
    if(current.left === null && current.right === null){
        if(current === this.root){
            this.roo = null
        }else if(isLeftChild){
            parent.left = null
        }else{
            parent.right = null
        }
    }
     // 删除节点有一个子节点
     else if(current.right === null){
        if(this.root === current){
            this.root = current.left
        }else if(isLeftChild){
            parent.left = current.left
        }else{
            parent.right = current.left
        }
     }else if(current.left === null){
         if(current == this.root){
             this.root = current.left
         }else if(isLeftChild){
             parent.left = current.right
         }else{
             parent.right = current.right
         }
     }
    //  删除节点有两个子节点
    else{
        let successor = getSuccessor(current);
        if(this.root === current){
            this.root = successor
        }else if(isLeftChild){
            parent.left = successor
        }else{
            parent.right = successor
        }
        successor.left = current.left
        function getSuccessor(delNode){
            let successerParent = delNode,
                successer = delNode,
                current = delNode.right;
            while(current !== null){
                successerParent = successer
                successer = current
                current =current.left
            }
            if(successer != delNode.right){
                successerParent.left = successer.right
                successer.right = delNode.right
            }
        }
        return true
    }
    return false
}

6.4 二叉树的应用

把二叉树转换成累加树将二叉搜索树变平衡二叉搜索树最大键值和

7、红黑树

7.1 红黑树的概述

红黑树也是一个自平衡的二叉搜索树。在红黑树中,每个节点都遵循以下规则:

  1. 每个节点不是红的就是黑的
  2. 树的根节点都是黑的
  3. 所有的叶子节点都是黑的
  4. 如果一个节点是红的,那么它的两个子节点都是黑的
  5. 不能有相邻的两个红节点
  6. 从给定的节点到它的后代节点的所有路径包含相同数量的黑色节点

8、图

8.1 图的概述

图是网路结构的抽象模型。主要研究的目的是事物之间的关系,顶点代表事物,边代表两个事物间的关系。

  • 顶点:图中的一个节点,如图中的某个村庄
  • 边:顶点和顶点之间的连线,如图中0-1有一条边,1-2有一条边,0-2没有边
  • 相邻顶点:一条边连接在一起的顶点称为相邻顶点,如图0-1是相邻的,0-2不相邻
  • 度:一个顶点的度是相邻顶点的数量,如图0顶点的数量是2
  • 路径:路径是顶点v1,v2,v3…vn的一个连续序列

8.2 图的常规操作

方法作用
addVertex(v)添加顶点
addEdge(v1,v2)添加边
toString()
bfs()广度遍历图
dfs()深度遍历图

8.3 用js封装图

function Graph() {
    //属性:顶点、边
    this.vertexes = []
    this.edges = new Dictionay()
}
// 添加顶点
Graph.prototype.addVertex = function(v){
    this.vertexes.push(v)
    this.edges.set(v, [])
}
// 添加边
Graph.prototype.addEdge = function (v1,v2){
    this.edges.get(v1).push(v2)
    this.edges.get(v2).push(v1)
}
Graph.prototype.toString = function (){
    let res = ''
    for(let i=0;i< this.vertexes.length; i++){
        res += this.vertexes[i] + '--->'
        let vEdges = this.edges.get(this.vertexes[i])
        for(let j=0;j < vEdges;j++){
            res += vEdges
        }
    }
    return res
}

8.4 图的应用

克隆图课程表除法求值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值