堆
堆的定义
堆是一种特殊的完全二叉树,其中每个节点的值都大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。
堆的性质
- 堆的根节点(最大堆的根节点是最大值,最小堆的根节点是最小值)。
- 堆的每个子树也是一个堆。
- 堆的节点数为 n,则其高度为 log2n。
堆的实现
堆的实现通常使用数组来表示,其中每个元素的索引表示节点在树中的位置。
堆的插入
堆的插入操作通常是将新元素添加到数组的末尾,然后通过上浮操作(sift up)将新元素移动到正确的位置。
堆的删除
堆的删除操作通常是将根节点删除,然后通过下沉操作(sift down)将最后一个元素移动到根节点的位置。
文章作者: wyf
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 wyf 的个人博客!
相关推荐
2025-03-11
N数之和
一、题目特征 给定一个整数数组 nums 和一个整数目标值 target,需要在该数组中找出并返回满足全部条件且不重复的N元组(或下标)。特别地,对于N的不同取值,N元组需要满足的附加条件也不完全相同。 二、思路 1.滑动窗口 对于要求返回N元组的题,设置四个指针使用for循环暴力求解的时间复杂度为 O(nn)O(n^n)O(nn)。由于题目不要求返回下标,因此我们可以使用sort()库函数将数组修改为有序数组,再结合滑动窗口法可以将右侧两个指针的遍历操作的时间复杂度由 O(n2)O(n^2)O(n2) 降低到 O(n)O(n)O(n),获得更快的效率。 2.去重操作 由于原数组中可能存在具有相同值的元素,这类题还需要考虑如何实现去重操作,保证结果中的数组互不相同。由于比较并删除相同数组比较困难,最好的办法是在遍历的过程中跳过具有相同值的元素,此处注意对于for循环的变量跳过的条件一定是本次的操作数与上一次的相同(nums[i] = nums[i-1])而不是和下一次进行比较然后跳过本轮遍历。因为for循环变量的取值范围:上轮操作 > 本轮操作 >...
2025-03-12
Manacher算法
Manacher算法 Manacher算法是一种用于在字符串中查找最长回文子串的算法。它通过将字符串转换为一个新的字符串,并利用回文的对称性来加速查找过程。也是一种动态规划算法。 时间复杂度 O(n)O(n)O(n) 空间复杂度 O(n)O(n)O(n) 算法步骤 1. 预处理 当回文串的长度为奇数时,回文串的中心是唯一的,不会出现重复,因此要保证回文串的长度为奇数。一奇一偶相加,结果为奇数。 为此,在开头插入一个不存在于原字符串中的特殊字符(通常是^),在结尾插入一个不存在于原字符串中的特殊字符(通常是$),在原字符串的每个字符之间插入一个不存在于原字符串中的特殊字符(通常是#),这样回文串的长度就变成了奇数。 123456def manacher(s): # 预处理字符串 T = '^#' + '#'.join(s) + '#$' n = len(T) P = [0] * n # 回文半径数组 C, R = 0, 0 # 回文中心和回文右边界 2....
2025-03-11
全排列问题
全排列问题 一、问题特点 给出一个数组,返回所有可能的全排列。其中“全排列”的定义如下: 将n个元素按照一定的顺序排列起来,所有的排列情况的集合叫全排列 全排列问题的整体思路和其他回溯问题相仿,但去重操作和其他问题有所不同,这是由其自身性质决定的: 排列问题中每一条路径都必须遍历原集合中所有的元素(终止条件恒为 path.size() == nums.size() ) 排列问题中每一种状态中元素的排列顺序必须各不相同 任何一条路径都不能重复遍历同一个元素 二、遍历方法 因为不能使用startIndex修剪搜索空间,每层遍历都要从nums[0]遍历到nums[nums.size()-1]。 路径中的状态不需要记录到结果数组中,终止条件恒为 path.size() ==...
2025-03-11
二分法
一、用途 在数组中查找某一特定值的函数并获取其下标。 二、限制条件 1.有序数组 所查找的数组中的所有元素必须按照从小到大或从大到小的顺序排列。 如果所查找的数组不是有序数组,也可使用sort()库函数将其转化为升序排列的有序数组后再进行查找。其中sort()函数位于C++的algorithm库中,其具体用法如下: 123456789101112#include <iostream>#include <vector> #include <algorithm>using namespace std; vector<int> arr = {1, 3, 5, 6, 9, 12};// 默认为升序排序sort(arr, arr + n); // 降序排列sort(arr, arr + n, greater<int>()); ...
2025-03-11
切割问题
切割问题 一、问题特点 这类问题通常会给出一个数组(或字符串),要求列举出所有满足特定条件的划分。其特点如下: 通常不允许改变原集合中元素的相对顺序 所求答案通常是若干组满足特定条件的划分 划分中的所有元素必须在原集合中连续取值 二、相关例题 (一)分割回文串 131.分割回文串(LeetCode) 题目要求: 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串 。返回 s 所有可能的分割方案。 回文串是正着读和反着读都一样的字符串。 示例: 输入:s = “aab” 输出:[[“a”,“a”,“b”],[“aa”,“b”]] 提示: 1 <= s.length <= 16 s 仅由小写英文字母组成 解题思路: 切割问题同样是回溯算法的典型应用,其解题思路和组合问题大致相同,同样需要用for循环加递归的方法遍历搜索树查找满足条件的解,又因为切割问题中不允许重复取值,所以仍需要startIndex标明切割的起始位置。和组合问题不同的是,切割问题每次添加到路径中的往往不是单个元素s[i],而是从[startIndex,...
2025-03-11
双指针法在链表中的应用
一、算法思想 在链表中寻找某一元素大多需要通过它的相邻元素才能找到该元素的地址。当我们对该元素进行删除、排序等操作时需要改变这个元素及其相邻元素的指针,但由于程序只能逐条执行,某些间接节点的地址在更改的过程中有丢失的风险,需要另设一个乃至多个指针保存这些将会丢失的地址,以免出现更改一个节点以后找不到下一节点的情况。 二、算法特性 1.适用条件 数据结构为链表 对链表中的某一元素进行删除,移位操作 2.时空复杂度 时间复杂度: O(n) 空间复杂度: O(1) 三、算法实例 206.反转链表 题目要求: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例1: 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例2: 输入:head = [1,2] 输出:[2,1] 解题思路:...
公告
欢迎来到我的博客!
