前端js学算法-实践

1、两数之和
const twoSum = (nums, target) => {
    const obj = {}
    for (let m = 0; m < nums.length; m++) {
        const cur = nums[m]
        const diff = target - cur
        if(obj.hasOwnProperty(diff)){ // 查询对象中是否存在目标值-当前值键值对
            console.log([obj[diff], m]) // 存在则直接获取差值key对应的值,即索引。m为当前索引
            break
        }else{
            obj[cur] = m // 存储当前值和当前索引
        }
    }
}


const twoSum = (nums, target) => {
    const obj = new Map()
    for (let m = 0; m < nums.length; m++) {
        const cur = nums[m]
        const diff = target - cur
        if(obj.has(diff)){
            console.log([obj.get(diff), m])
            break
        }else{
            obj.set(cur, m)
        }
    }
}


twoSum([1,2,3,4,5,6,76], 9) // [3, 4]
twoSum([3,3], 6)            // [0, 1]
twoSum([1,2,3,4,5,6,3], 6)  // [1, 3]
2、字母异位词
var strs = ["eat", "tea", "tan", "ate", "nat", "bat"];
var obj = {};
var groupAnagrams = function () {
  strs.forEach((item) => {
    const st = item.split("").sort().join("");
    if (!obj[st]) obj[st] = new Set();
    obj[st].add(item);
  });
  var res = [];
  Object.values(obj).forEach((item) => {
    res.push([...item]);
  });
  console.log(res);
};
groupAnagrams();
// Output: [ [ 'eat', 'tea', 'ate' ], [ 'tan', 'nat' ], [ 'bat' ] ]
3、最长连续序列
var longestConsecutive = function(nums) {
    const numsNew = new Set(nums.sort((a,b) => a - b))
    const arr = []
    const numsNewList = [...numsNew]
    numsNewList.forEach((val, index) =>{
        const nextval = numsNewList[index + 1]
        const arrlen = arr.length
        const arrLast = arr[arrlen - 1]
        if(arrLast){
            const arrLastlen = arrLast.length
            const arrLastVal = arrLast[arrLastlen - 1]
            if(arrLastVal + 1 === val){
                arrLast.push(val)
            }else{
                arr.push([val])
            }
        }else{
            arr.push([val])
        }
    })
    const aaa = arr.sort((a, b) => b.length - a.length);
    return aaa[0].length
}
4、哈希表与链表

        哈希表是无序的快速查找工具,链表是有序的动态序列容器

    哈希表:

核心特性

  1. 无序性
    • 元素的存储位置由哈希函数计算决定,与插入顺序无关。
    • 遍历时元素的顺序不可预测(取决于哈希桶的分布)。
  2. 快速访问
    • 通过键(Key)直接定位值(Value),时间复杂度接近 O(1)
  3. 存储结构
    • 底层通常是数组 + 链表/红黑树(解决哈希冲突)。
  4. 典型应用
    • 字典、缓存、快速查找场景(如数据库索引)。

js中的对象是基于哈希表结构的,而哈希表的查找时间复杂度为O(1),访问方式:直接通过键访问(O(1))。所以很多人喜欢用对象来做映射,减少遍历循环。

利用数组索引快速查找数据的特性,无序(由哈希函数决定),通过实现一个hash函数将key转化为唯一的索引,对应数组中的一个位置。所以具有快速存取删数据的特性

      优点:

  1. 高效的查找:哈希表可以在常数时间复杂度内进行查找操作,即 O(1)。这使得它在需要快速查询数据的场景中非常有用。

  2. 快速的插入和删除:哈希表同样可以在常数时间复杂度内执行插入和删除操作,这使得它非常适合需要频繁更新数据的场景。

  3. 空间利用率高:哈希表可以根据实际数据量动态调整大小,以尽可能减少内存的使用。

  4. 编码简单:哈希表的实现相对简单,只需设计一个合适的哈希函数即可

      缺点: 

  1. 冲突处理:当两个不同的键被映射到同一个索引位置时,会发生冲突。解决冲突的方法有很多种,但不同的方法对性能的影响也不同。

  2. 哈希函数的选择:选择一个好的哈希函数对于避免冲突以及提高性能至关重要。如果选择的哈希函数不好,可能会导致冲突增多或者性能下降。

  3. 不支持顺序访问:与数组或链表不同,哈希表中的元素没有特定的顺序。如果需要按照某种顺序访问元素,可能需要对哈希表进行额外的处理

	class HashTable {
		size: number
		table: any[]
		constructor(size: number) {
			this.size = size
			this.table = Array.from({length: size}, () => [])
		}

		hash(key: string) {
			let h = 0
			for (let i = 0; i < key.length; i++) {
				h += key.charCodeAt(i)
			}
			return h % this.size
		}
		// 设置和更新
		set(key, value) {
			const index = this.hash(key)
			let bucket = this.table[index]
			const cur = bucket?.find(item => item.key === key)
			if (cur) {
				cur.value = value
			} else {
				bucket = []
				bucket.push({key, value})
			}
		}
		get(key: string) {
			const index = this.hash(key)
			const bucket = this.table[index]
			const cur = bucket?.find(item => item.key === key)
		  return	cur ? cur.value : null
		}
		delete(key: string) { 
			const index = this.hash(key)
			const bucket = this.table[index]
			const findex = bucket?.findIndex(item => item.key === key)
			if (findex !== -1) {
				this.table.splice(findex, 1)
				return true
			} else {
				return false 
			}
		}
		has(key) {
			return !!this.get(key)
		}
	}

	const hashtable = new HashTable(100)
	hashtable.set('name', 'zhangsan')
	hashtable.set('age', '20')
    链表:

核心特性

  1. 有序性(按插入顺序)
    • 元素通过节点指针显式连接,遍历顺序始终是插入顺序。
    • 若需要排序,需额外维护(如有序链表)。
  2. 顺序访问
    • 查找元素必须从头节点开始遍历,时间复杂度为 O(n)
  3. 存储结构
    • 节点包含数据(Data)和指针(Next/Prev)。
  4. 典型应用
    • 需要频繁插入/删除的场景(如LRU缓存淘汰算法)

链表格是一种线性数据结构,类似于数组,有序(按插入顺序或显式排序),  访问方式:顺序遍历(O(n))

。但不像数组的元素存储在特定的存储器位置或索引中,链表格的每个元素都是一个独立的对象,其中包含一个指针或链接指向列表中的下一个对象。

每一个元素(通常 称为节点)包含两个项目:存储的数据和到下一个节点的链接,这些数据可以是任何有效数据类型

    优点:

        可以很容易地从链表中删除或添加节点,而无需重组整个数据结构。这是它相对于数组的一个优势

  • 动态内存分配:链表不需要在创建时就确定大小,它可以根据需要动态地增加或减少节点,这使得内存利用更加灵活。

  • 插入和删除效率高:在链表中添加或删除节点时,只需要修改相关节点的指针,不必像数组那样移动大量元素,这样操作起来更快。

  • 灵活性:链表可以轻松地实现各种复杂的数据结构,如双向链表、循环链表等,为不同的算法实现提供了便利

    缺点:

        链表的搜索操作很慢,与数组不同,不允许随机访问数据元素,必须从第一个节点开始按顺序访问节点。由于需要储存指针,相较于数组需要更多内存,

  • 访问效率低:链表不支持随机访问,访问特定位置的节点需要从头开始遍历,这在数据量大时会影响效率1

  • 额外的内存开销:每个链表节点都需要额外的存储空间来存储指针,这与数组相比是一种空间上的浪费

	class Node{
		data
		next
		construcotr(data) { 
			this.data = data;
			this.next = null
		}
	}
	
	class linkedList{
		head
		size
		constryctor() {
			this.head = null
			this.size = 0
		}
		append(data) { 
			const node = new Node(data)
			if (!this.head) {
				this.head = node
			} else {
				const current = this.head
				while (current.next) {
					current = current.next
				}
				current.next = node
			}
			this.size++
		}
		// get(data){ 
		// 	const head = this.head
		// 	while (head.next) {
		// 		if (head.data === data) {
		// 			return head.next
		// 		}
		// 	}
		// }
	
		delete (data){ 
			if (!this.hear) return
			
			if (this.head.data === data) {
				this.head = this.head.next
			} else {
				let current = this.head
				let prev = null
				while (current && current.data !== data) {
					current = current.next
					prev = current
				}
				if (current) {
					prev.next = current.next
				}
			}
			this.size--
		}
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值