JS数据结构和算法

本文详细介绍了JavaScript中常用的数据结构,如栈、队列、链表、集合、字典,以及树、图、堆等。通过LeetCode题目解析,深入探讨了各种数据结构的实现和操作,包括排序和搜索算法,如冒泡排序、二分搜索等。此外,还涉及动态规划和贪心算法的基本思想和应用实例。
摘要由CSDN通过智能技术生成

一、栈

在这里插入图片描述
在这里插入图片描述
leetcode题目:
在这里插入图片描述
在这里插入图片描述

//方法一:栈
var isValid = function (s) {
    if (s.length % 2 === 1) return false;
    const stack = [];
    for (var i = 0; i < s.length; i++) {
        var c = s[i];
        if (c === '(' || c === '[' || c === '{') {
            stack.push(c);
        } else {
            var top = stack[stack.length - 1];
            if (
                (top === '(' && c === ')') ||
                (top === '[' && c === ']') ||
                (top === '{' && c === '}')
            ) {
                stack.pop();
            }
            else {
                return false;
            }
        }
    }
    return stack.length === 0;
};

二、队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
leetcode题目:
在这里插入图片描述

三、链表

在这里插入图片描述
在这里插入图片描述

js中没有链表,但可以用对象object来模拟链表:

const a = {
    val: 'a'
}
const b = {
    val: 'b'
}
const c = {
    val: 'c'
}
const d = {
    val: 'd'
}
a.next = b;
b.next = c;
c.next = d;

// 遍历链表
let p = a;
while (p) {
    console.log(p.val);
    p = p.next;
}

//插入链表
const e = {
    val: 'e'
};
c.next = e;
e.next = d;


// 刪除链表
c.next = d;

总结:给链表添加一个虚拟头结点

const ret = new ListNode(0, head);
return ret;

leecode题目:
在这里插入图片描述

解题思路:

  1. 无法直接获取被删除节点的上个节点。
  2. 将被删除的节点转移到下个节点。

解题步骤:

  1. 将被删除节点的值改为下个节点的值。
  2. 删除下个节点。

本题时间复杂度和空间复杂度均为:O(1)

leecode题目:206. 反转链表
在这里插入图片描述

思路:

  1. 反转两个节点:将n+1的next指向n.
  2. 反转多个节点:双指针遍历链表,重复上述操作。

步骤:

  1. 双指针一前一后遍历链表。
  2. 反转双指针。

时间复杂度:O(n) 空间复杂度:O(1)

var reverseList = function (head) {
    let p1 = null;
    let p2 = head;
    while (p2) {
        let temp = p2.next; //提前保存p2的下一个节点
        p2.next = p1; //反转 
        p1 = p2; //把p2的值给p1,相当于p1往前移动一位
        p2 = temp; //把p2.next赋值给p2,相当于p2往前移动一位
    }
    return p1; //循环结束后,p2指向null,返回p1即可
};

leecode题目:2. 两数相加【较难】
在这里插入图片描述

解题步骤:

  1. 新建一个空链表。
  2. 遍历相加的两个链表,模拟相加操作,将个位数追加到新链表上,将十位数留到下一位去相加。

时间/空间复杂度:O(max(m,n)),其中 m 和 n 分别为两个链表的长度.

var addTwoNumbers = function (l1, l2) {
    const l3 = new ListNode();
    let p1 = l1;
    let p2 = l2;
    let p3 = l3;
    let carry = 0;
    while (p1 || p2) {
        const v1 = p1 ? p1.val : 0;
        const v2 = p2 ? p2.val : 0;
        const v3 = v1 + v2 + carry;
        carry = Math.floor(v3 / 10);
        p3.next = new ListNode(v3 % 10);
        if (p1) p1 = p1.next;
        if (p2) p2 = p2.next;
        p3 = p3.next;
    }
    if (carry) {
        p3.next = new ListNode(carry);
    }
    return l3.next;
};

leecode题目:141. 环形链表
在这里插入图片描述

思路:
用一快一慢两个指针遍历链表,如果指针能够相逢,说明链表有环。

时间复杂度:O(n)
空间复杂度:O(1)

var hasCycle = function (head) {
    let p1 = head;
    let p2 = head;
    while (p1 && p2 && p2.next) {
        p1 = p1.next;
        p2 = p2.next.next;
        if(p1===p2){
            return true;
        }
    }
    return false;
};

leecode 题目:21. 合并两个有序链表
在这里插入图片描述

思路:双指针

  1. 新建一个链表,作为返回的结果。
  2. 用指针遍历两个有序链表,并比较两个链表的当前节点,较小者先接入新链表,并将指针后移一步。
  • 时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。
  • 空间复杂度:O(1)
var mergeTwoLists = function (l1, l2) {
    let res = new ListNode(0);
    let p = res;
    let p1 = l1;
    let p2 = l2;
    while (p1 && p2) {
        if (p1.val < p2.val) {
            p.next = p1;
            p1 = p1.next;
        } else {
            p.next = p2;
            p2 = p2.next;
        }
        p = p.next;
    }
    if (p1) {
        p.next = p1;
    }
    if (p2) {
        p.next = p2;
    }
    return res.next;
};

四、集合

  • 一种无序且唯一的数据结构。

  • ES6中有集合,名为set。

  • 集合的常用操作:去重、判断某元素是否在集合中、求交集…

    // 查看集合
    const arr = [1, 1, 2, 2, 2];
    const set = new Set(arr)//Set(2) {1, 2}
    //查看集合的长度
    console.log(set.size);//2

    // 去重
    const arr = [1, 1, 2, 2, 2];
    const arr2 = […new Set(arr)];
    console.log(arr2); //[ 1, 2 ]

    // 判断元素是否在集合中
    const set = new Set(arr);
    const has = set.has(3);
    console.log(has); //false

    //求交集
    const set2 = new Set([2, 3]);
    const set3 = new Set([…set].filter(item => set2.has(item)));
    console.log(set3); //{ 2 }

ES6中的set:

let mySet = new Set();

mySet.add(1);
mySet.add(5);
mySet.add(5);
mySet.add('some text');
let o = { a: 1, b: 2 };
mySet.add(o);
mySet.add({ a: 1, b: 2 });

const has = mySet.has(o);

mySet.delete(5);

for(let [key, value] of mySet.entries()) console.log(key, value);

const myArr = Array.from(mySet);

const mySet2 = new Set([1,2,3,4]);

const intersection = new Set([...mySet].filter(x => mySet2.has(x)));
const difference = new Set([...mySet].filter(x => !mySet2.has(x)));

leecode题目:
在这里插入图片描述

var intersection = function (nums1, nums2) {
    nums1 = new Set(nums1);
    nums2 = new Set(nums2);
    let res = [...nums1].filter(item=>nums2.has(item));
    return res;
};
//时间复杂度:O(m*n)
//空间复杂度:O(m), m为去重后的数组长度

五、字典

  • 与集合类似,字典也是一种存储唯一值的数据结构,但它是以键值对的形式来存储的。

  • ES6中有字典,名为Map。

  • 字典的常用操作:键值对的增删改查。

    const m = new Map();

    // 增
    m.set(‘a’, ‘aa’);
    m.set(‘b’, ‘bb’);

    //查看字典m:
    //Map(2) {“a” => “aa”, “b” => “bb”}
    //字典的长度
    console.log(m.size);//2

    // 删
    m.delete(‘b’);
    // m.clear();

    // 改
    m.set(‘a’, ‘aaa’);

    //查
    m.get(‘a’); //‘aaa’

    //判断a是否存在字典中
    m.has(‘a’); //true

leecode题目:
在这里插入图片描述

var intersection = function (nums1, nums2) {
    let map = new Map(),
        arr = [];
    nums1.forEach(n => {
        map.set(n, true);
    });
    nums2.forEach(n => {
        if (map.get(n)) {            
            map.delete(n);
            arr.push(n);
        };
    });
    return arr;
};
//时间复杂度:O(m+n)
//空间复杂度:O(m)

leecode题目&#x

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值