LeetCode-Notes 数据结构篇:哈希表与二叉树

LeetCode-Notes 数据结构篇:哈希表与二叉树

【免费下载链接】leetcode-notes 🐳 LeetCode 算法笔记:面试、刷题、学算法。在线阅读地址:https://datawhalechina.github.io/leetcode-notes/ 【免费下载链接】leetcode-notes 项目地址: https://gitcode.com/datawhalechina/leetcode-notes

文章概要的内容包括哈希表的实现原理、冲突解决策略及其在LeetCode题目中的应用,以及二叉树的基础知识、遍历方式和实战题目解析。通过代码示例和流程图,详细讲解了哈希表和二叉树的核心概念与操作。

哈希表的实现与应用

哈希表(Hash Table)是一种高效的数据结构,广泛应用于数据存储和快速查找场景。它通过哈希函数将键映射到存储位置,从而实现平均时间复杂度为 O(1) 的插入、删除和查找操作。本节将详细介绍哈希表的实现原理及其在 LeetCode 题目中的应用。

哈希表的基本原理

哈希表的核心思想是通过哈希函数将键(Key)转换为数组的索引(Index),从而直接访问对应的存储位置。以下是哈希表的关键组成部分:

  1. 哈希函数:将键映射到数组索引的函数。理想的哈希函数应满足均匀分布,避免冲突。
  2. 冲突解决:当多个键映射到同一索引时,需采用冲突解决策略,常见方法有:
    • 链地址法:每个索引位置存储一个链表,冲突的键值对存储在链表中。
    • 开放地址法:冲突时寻找下一个空闲位置存储。
哈希表的实现示例

以下是一个基于链地址法的哈希表实现(Python):

class HashTable:
    def __init__(self, size=10):
        self.size = size
        self.table = [[] for _ in range(size)]

    def _hash(self, key):
        return hash(key) % self.size

    def insert(self, key, value):
        index = self._hash(key)
        for pair in self.table[index]:
            if pair[0] == key:
                pair[1] = value
                return
        self.table[index].append([key, value])

    def get(self, key):
        index = self._hash(key)
        for pair in self.table[index]:
            if pair[0] == key:
                return pair[1]
        raise KeyError(f"Key {key} not found")

    def remove(self, key):
        index = self._hash(key)
        for i, pair in enumerate(self.table[index]):
            if pair[0] == key:
                self.table[index].pop(i)
                return
        raise KeyError(f"Key {key} not found")

哈希表的应用场景

哈希表在算法题目中的应用非常广泛,以下是几个典型的应用场景:

  1. 快速查找:如统计频率、去重等。
  2. 缓存设计:如 LRU 缓存机制。
  3. 字符串处理:如判断字符串是否为变位词。
示例题目分析

题目:两数之和(LeetCode 1)

给定一个整数数组 nums 和一个目标值 target,请你在数组中找出和为目标值的两个整数,并返回它们的索引。

哈希表解法:

def two_sum(nums, target):
    hash_map = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in hash_map:
            return [hash_map[complement], i]
        hash_map[num] = i
    return []

时间复杂度分析:

  • 插入和查找操作均为 O(1),整体时间复杂度为 O(n)。

哈希表的性能优化

  1. 选择合适的哈希函数:减少冲突概率。
  2. 动态扩容:当负载因子(元素数量/表大小)超过阈值时,扩容哈希表。
  3. 冲突处理优化:如使用更高效的链表或红黑树替代普通链表。

总结

哈希表是一种高效的数据结构,适用于需要快速查找和插入的场景。通过合理的哈希函数设计和冲突解决策略,可以显著提升其性能。在 LeetCode 题目中,哈希表常用于解决查找、统计和缓存设计等问题。

二叉树的基础知识与遍历

二叉树是数据结构中非常重要的一种非线性结构,广泛应用于算法设计和问题求解中。本节将介绍二叉树的基础知识,包括二叉树的定义、性质以及常见的遍历方式(前序、中序、后序和层次遍历),并通过代码示例和流程图帮助读者深入理解。


二叉树的定义与性质

二叉树(Binary Tree)是每个节点最多有两个子节点的树结构,通常称为左子节点和右子节点。它具有以下性质:

  1. 节点数量关系:对于一棵非空二叉树,如果其叶子节点数为 ( n_0 ),度为 2 的节点数为 ( n_2 ),则满足 ( n_0 = n_2 + 1 )。
  2. 高度与节点数:高度为 ( h ) 的二叉树最多有 ( 2^h - 1 ) 个节点。
  3. 完全二叉树:除了最后一层外,其他层的节点数都达到最大值,且最后一层的节点都集中在左侧。
代码示例:二叉树的节点定义
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

二叉树的遍历方式

二叉树的遍历是指按照某种顺序访问树中的所有节点。常见的遍历方式包括:

  1. 前序遍历(Preorder Traversal):根节点 → 左子树 → 右子树。
  2. 中序遍历(Inorder Traversal):左子树 → 根节点 → 右子树。
  3. 后序遍历(Postorder Traversal):左子树 → 右子树 → 根节点。
  4. 层次遍历(Level Order Traversal):按层次从上到下、从左到右访问节点。
前序遍历示例代码
def preorder_traversal(root):
    if not root:
        return []
    return [root.val] + preorder_traversal(root.left) + preorder_traversal(root.right)
中序遍历示例代码
def inorder_traversal(root):
    if not root:
        return []
    return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)
层次遍历示例代码
from collections import deque

def level_order_traversal(root):
    if not root:
        return []
    queue = deque([root])
    result = []
    while queue:
        level = []
        for _ in range(len(queue)):
            node = queue.popleft()
            level.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        result.append(level)
    return result

遍历方式对比

遍历方式访问顺序应用场景
前序遍历根 → 左 → 右复制二叉树、表达式树求值
中序遍历左 → 根 → 右二叉搜索树的有序输出
后序遍历左 → 右 → 根删除二叉树、计算表达式树
层次遍历按层次从上到下、从左到右计算二叉树的高度、广度优先搜索

遍历流程图

以下是一个二叉树的遍历流程图示例(前序遍历):

mermaid


总结

通过本节的学习,读者应掌握二叉树的基本概念、性质以及四种常见的遍历方式。每种遍历方式都有其独特的应用场景,理解它们的实现原理有助于在实际问题中灵活运用。接下来的练习题目将帮助巩固这些知识。

二叉搜索树与并查集

二叉搜索树(Binary Search Tree, BST)和并查集(Union-Find)是两种在算法和数据结构中广泛应用的工具。它们分别用于高效的数据查询和动态连通性问题。本文将深入探讨它们的原理、实现方式以及典型应用场景。

二叉搜索树

二叉搜索树是一种特殊的二叉树,满足以下性质:

  1. 左子树的所有节点值小于根节点的值。
  2. 右子树的所有节点值大于根节点的值。
  3. 左右子树也分别为二叉搜索树。
基本操作
  • 插入:从根节点开始,比较插入值与当前节点值,决定向左或向右子树递归插入。
  • 查找:类似插入,根据比较结果决定搜索方向。
  • 删除:分为三种情况:
    • 无子节点:直接删除。
    • 有一个子节点:用子节点替换当前节点。
    • 有两个子节点:用右子树的最小节点替换当前节点。

mermaid

应用场景
  • 动态数据集合的快速查找、插入和删除。
  • 实现有序映射或集合。

并查集

并查集是一种用于处理不相交集合合并及查询问题的数据结构。它支持两种操作:

  1. Find:查询某个元素所属的集合。
  2. Union:合并两个集合。
实现方式
  • 路径压缩:优化Find操作,使树更扁平。
  • 按秩合并:优化Union操作,将小树合并到大树下。

mermaid

应用场景
  • 图的连通性问题。
  • 社交网络中的好友关系管理。

代码示例

二叉搜索树插入
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def insert(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert(root.left, val)
    else:
        root.right = insert(root.right, val)
    return root
并查集实现
class UnionFind:
    def __init__(self, size):
        self.parent = list(range(size))
        self.rank = [0] * size

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])  # Path compression
        return self.parent[x]

    def union(self, x, y):
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        if self.rank[x_root] < self.rank[y_root]:
            self.parent[x_root] = y_root
        else:
            self.parent[y_root] = x_root
            if self.rank[x_root] == self.rank[y_root]:
                self.rank[x_root] += 1

性能对比

数据结构查找复杂度插入复杂度删除复杂度空间复杂度
二叉搜索树O(log n)O(log n)O(log n)O(n)
并查集O(α(n))O(α(n))-O(n)

注:α(n)为反阿克曼函数,通常认为其值小于5。

通过本文的介绍,读者可以掌握二叉搜索树和并查集的核心原理与实现方法,并在实际问题中灵活运用。

实战题目解析与练习

在数据结构的学习中,哈希表和二叉树是两个非常重要的部分。哈希表以其高效的查找和插入操作著称,而二叉树则是许多高级数据结构和算法的基础。本节将通过具体的LeetCode题目,深入解析哈希表和二叉树的应用场景和解题技巧,并提供相关练习题目,帮助读者巩固所学知识。

哈希表实战题目解析

题目1:两数之和(LeetCode 1)

题目描述:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

解题思路

  1. 使用哈希表存储数组中每个元素的值及其索引。
  2. 遍历数组,对于每个元素,检查目标值减去当前元素的差是否在哈希表中。
  3. 如果存在,则返回两个元素的索引。

代码示例

def twoSum(nums, target):
    hash_map = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in hash_map:
            return [hash_map[complement], i]
        hash_map[num] = i
    return []

复杂度分析

  • 时间复杂度:O(n),只需遍历一次数组。
  • 空间复杂度:O(n),哈希表存储最多n个元素。
题目2:无重复字符的最长子串(LeetCode 3)

题目描述:给定一个字符串,找出其中不含有重复字符的最长子串的长度。

解题思路

  1. 使用滑动窗口和哈希表记录字符的最新位置。
  2. 维护一个窗口,窗口内无重复字符,每次移动右边界。
  3. 如果遇到重复字符,移动左边界到重复字符的下一个位置。

代码示例

def lengthOfLongestSubstring(s):
    char_map = {}
    left = max_len = 0
    for right, char in enumerate(s):
        if char in char_map and char_map[char] >= left:
            left = char_map[char] + 1
        char_map[char] = right
        max_len = max(max_len, right - left + 1)
    return max_len

复杂度分析

  • 时间复杂度:O(n),遍历字符串一次。
  • 空间复杂度:O(min(m, n)),m为字符集大小。

二叉树实战题目解析

题目1:二叉树的中序遍历(LeetCode 94)

题目描述:给定一个二叉树的根节点,返回它的中序遍历。

解题思路

  1. 递归法:按照左子树、根节点、右子树的顺序遍历。
  2. 迭代法:使用栈模拟递归过程。

代码示例(递归法)

def inorderTraversal(root):
    result = []
    def helper(node):
        if not node:
            return
        helper(node.left)
        result.append(node.val)
        helper(node.right)
    helper(root)
    return result

复杂度分析

  • 时间复杂度:O(n),每个节点访问一次。
  • 空间复杂度:O(n),递归栈的深度。
题目2:对称二叉树(LeetCode 101)

题目描述:给定一个二叉树,检查它是否是镜像对称的。

解题思路

  1. 递归法:比较左右子树的对称节点。
  2. 迭代法:使用队列或栈逐层比较。

代码示例(递归法)

def isSymmetric(root):
    def helper(left, right):
        if not left and not right:
            return True
        if not left or not right:
            return False
        return left.val == right.val and helper(left.left, right.right) and helper(left.right, right.left)
    return helper(root.left, root.right) if root else True

复杂度分析

  • 时间复杂度:O(n),每个节点访问一次。
  • 空间复杂度:O(n),递归栈的深度。

练习题目

题目编号题目名称难度相关知识点
1两数之和简单哈希表
3无重复字符的最长子串中等哈希表、滑动窗口
94二叉树的中序遍历简单二叉树、递归
101对称二叉树简单二叉树、递归

通过以上题目和解析,读者可以更好地理解哈希表和二叉树的应用场景,并通过练习题目巩固所学知识。

总结

哈希表和二叉树是数据结构中非常重要的两种结构,哈希表适用于快速查找和插入的场景,而二叉树则是许多高级算法的基础。通过本文的学习,读者应掌握哈希表的设计与优化方法,以及二叉树的遍历与应用技巧。结合实战题目解析和练习,可以进一步巩固这些知识并提升算法解题能力。

【免费下载链接】leetcode-notes 🐳 LeetCode 算法笔记:面试、刷题、学算法。在线阅读地址:https://datawhalechina.github.io/leetcode-notes/ 【免费下载链接】leetcode-notes 项目地址: https://gitcode.com/datawhalechina/leetcode-notes

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值