
算法与数据结构
文章平均质量分 86
恋喵大鲤鱼
一条不止于编码的鱼。
展开
-
基数树简介
基数树(Radix Trie)也叫基数特里树或压缩前缀树,是一种多叉树,一种更节省空间的 Trie(前缀树)。基数树中作为唯一子结点的每个结点都与其父结点合并,每个内部结点的子结点数最多为基数树的基数 r,r 为正整数且等于2^n(n>=1)。这使得基数树更适用于对于较小的集合(尤其是字符串很长的情况下)和有很长相同前缀的字符串集合。不像一般的 Trie,基数树的边可以是一个或者多个元素。原创 2023-03-31 18:41:00 · 1662 阅读 · 0 评论 -
定时器的实现原理
一个时间轮是一个环形结构,可以想象成时钟,分为很多格子,一个格子代表一段时间(越短 Timer 精度越高),并用一个 List 保存在该格子上到期要执行的所有任务。定时器在各种场景都需要用到,比如游戏的 Buff 实现,Redis 中的过期任务,Linux 中的定时任务等等。如果任务的时间跨度很大,数量也多,传统的时间轮会造成任务的 round 很大,单个格子的任务 List 很长,并会维持很长一段时间。此时需要调度一个 3s 后执行的任务,显然应该加入到(0+3=3)的方格中,指针再走3次就可以执行了。原创 2023-06-24 21:46:52 · 1580 阅读 · 0 评论 -
搜索旋转排序数组(LeetCode 33)
这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6] 和 [7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的,其他也是如此。将旋转排序数组均分,一定有一部分的数组是有序的。原创 2023-06-19 14:36:47 · 742 阅读 · 0 评论 -
字典树简介
字典树(Trie)又名前缀树或单词查找树,最初是由美国计算机科学家 Edward Fredkin 在 1960 年提出。字典树是一种基于字符串序列的树形结构,可以高效地存储和检索字符串集合中的所有字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。字典树的优点是利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。字典树的核心思想是空间换时间,利用字符串的公共前缀减少查询时间以提高查询效率。原创 2023-03-30 11:14:47 · 1864 阅读 · 1 评论 -
哈希树简介
哈希树(Hash Tree),在密码学及计算机科学中是一种树形数据结构,每个叶节点均以数据块的哈希作为标签,而除了叶节点以外的节点则以其子节点标签的加密哈希作为标签。哈希树能够高效、安全地验证大型数据结构的内容,是哈希链的推广形式。哈希树的概念由瑞夫·墨克于 1979 年申请专利,故亦称墨克树(Merkle tree)。原创 2023-03-28 17:08:28 · 3527 阅读 · 0 评论 -
一文读懂胜者树与败者树
胜者树和败者树是在排序和归并排序算法中常用的两种数据结构,它们在大规模数据排序中具有高效性和良好的稳定性。本篇博客将详细介绍这两种数据结构。原创 2023-03-11 22:40:00 · 6879 阅读 · 1 评论 -
小于 n 的最大数
如果没有相同的数字时,尝试是否有比当前数字更小的,有的话选更小的数字里最大的,剩下的用最大数字。都没有就向前回溯看前一个有没有更小的。数组 A 中给定可以使用的 1~9 的数,返回由数组 A 中的元素组成的小于 n 的最大数。示例 1:A={1, 2, 9, 4},n=2533,返回 2499。示例 2:A={1, 2, 5, 4},n=2543,返回 2542。示例 3:A={1, 2, 5, 4},n=2541,返回 2525。示例 4:A={1, 2, 9, 4},n=2111,返回 1999。原创 2022-09-21 22:48:03 · 5297 阅读 · 2 评论 -
设计循环队列(leetcode 622)
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。我们可以通过一个数组进行模拟,通过操作数组的索引构建一个虚拟的首尾相连的环。循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。当队列空时,rear 等于 front,但是当只有一个元素时,rear 也等于 front。当然也可以使用链表来实现,过程类似。原创 2022-09-20 12:36:49 · 421 阅读 · 0 评论 -
逆波兰表达式求值(leetcode 150)
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 )。该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * )。假设表达式长度为 n,那么操作数的个数为 ceil(n/2) 向上取整。逆波兰表达式的特点是:没有括号,运算符总是放在和它相关的操作数之后。因此,逆波兰表达式也称后缀表达式。通过观察逆波兰表达式的求值过程可以发现,整个过程就是操作数入栈出栈的过程。整个逆波兰表达式遍历完毕之后,栈内只有一个元素,该元素即为逆波兰表达式的值。原创 2022-09-19 21:58:17 · 897 阅读 · 0 评论 -
归并排序
实现二路归并排序。原创 2022-09-17 13:31:31 · 399 阅读 · 0 评论 -
有效的括号(leetcode 20)
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。原创 2022-09-14 22:47:47 · 377 阅读 · 0 评论 -
两数相加(leetcode 2)
具体而言,如果当前两个链表处相应位置的数字为 n1 和 n2,结果为 (n1+n2) mod 10,进位为 (n1+n2) / 10。给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位数字。遍历两个链表,将节点值相加,并与当前位置的进位值相加。如果产生进位,则将进位带到下一对节点。注意一点,如果两个链表最后一个节点产生了进位,需要生成新的节点。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。请你将两个数相加,并以相同形式返回一个表示和的链表。原创 2022-09-13 16:52:21 · 328 阅读 · 0 评论 -
拼写单词(leetcode 1160)
显然,对于一个单词 word,只要其中的每个字母的数量都不大于 chars 中对应的字母的数量,那么就可以用 chars 中的字母拼写出 word。所以我们只需要用一个哈希表存储 chars 中每个字母的数量,再用一个哈希表存储 word 中每个字母的数量,最后将这两个哈希表的键值对逐一进行比较即可。输入:words = [“cat”,“bt”,“hat”,“tree”], chars = “atach”注意:每次拼写(指拼写词汇表中的一个单词)时,chars 中的每个字母都只能用一次。原创 2022-09-09 13:58:37 · 231 阅读 · 0 评论 -
打印 A-Z 26 个字母的所有子集
数值中每一个比特位非零,表示该子集中包含对应位置的字母。同理,针对26个字母,我们只需要遍历0~有一个集合由A-Z这26个字母组成,打印这个集合的所有子集,每个子集一行,不要使用递归。鄙人于2018年在腾讯内部转岗面试时遇到了该题,还是挺常见的一道算法题,必须掌握。如果想打印26的大写字母的所有子集,只需要将n改为26即可。,检查每一个比特位是否为1,即可打印所有子集。可以发现数值范围是0到。......原创 2018-05-24 20:26:28 · 2296 阅读 · 0 评论 -
不用 sizeof 判断操作系统是 32 还是 64 位
2018上半年折腾了一回,想换个后台开发岗尝试锻炼一下自己,面了三个部门,将有关有意思的题目汇总记录下来,供大家参考。解法一: 我们知道,C/C++中,32位系统下编译生成的程序,书写代码时,整形数值默认取值范围是-2^31至2^31-1,加上数值后缀L,表示长整型,取值范围也是-2^31至2^31-1,加上LL表示尝尝整型数值,取值范围是-2^63至2^63-1。64位系统下编译生成的64......原创 2018-05-24 01:12:28 · 2966 阅读 · 6 评论 -
找出无序数组中比左边大比右边小的元素
题目:从长度为n的数组中找出同时满足下面两个条件的元素,时间复杂度为O(n)。 (1)该元素比放在它前面的所有元素都大; (2)该元素比放在它后面的所有元素都小。...原创 2018-05-29 10:36:50 · 6738 阅读 · 3 评论 -
rand1 生成 rand9
这是一道我于20220706周三上午于科兴科学园D1参与富图二面遇到的算法题。给定一个函数rand1会50%的概率输出0和1,请利用rand1实现rand9,等概率地输出0~9这10个数字。原创 2022-07-18 15:49:06 · 385 阅读 · 0 评论 -
颠倒二进制位(leetcode 190)
输入的二进制串00000010100101000001111010011100表示无符号整数43261596,因此返回964176192,其二进制表示形式为00111001011110000010100101000000。输出964176192(00111001011110000010100101000000)算法要现实的是将数值的位做个颠倒,只需遍历数值的每一位放到对应的位置即可,可以使用移位来实现。问题反转给定的32位无符号整数的二进制位。输入n=964176192。......原创 2022-06-28 16:44:52 · 546 阅读 · 2 评论 -
初识布隆过滤器
假如你的服务后台存储有大量数据,通过缓存提高查询效率,当缓存中不存某条记录再去数据库中查询,这就可以大大减少对数据库的请求压力。但是有一天某黑客构建大量不存在于缓存中的 key 发起缓存穿透攻击,在QPS足够高的情况下,有可能会把数据库压跨,这种情况下该怎么办呢?上面这个场景使用布隆过滤器最适合不过了,因为我们只要知道某个 key 对应的记录不存在于数据库就行了,恰好布隆过滤器就是为了解决这个问题而生。布隆过滤器(Bloom Filter)是1970年由布隆提出的。它由一个很长的二进制数组和一系列哈希函数组原创 2021-02-23 00:58:33 · 687 阅读 · 0 评论 -
判断一个数是不是素数
1.素数的定义素数又名质数,指除了 1 和本身外不再有其他因数的自然数。规定 0 和 1 既不是质数也不是合数,最小的质数是 2,最小的合数是 4。下面给出常见判断方法,效率依次提升,以 Golang 为例给出实现。2.直接法给定数 n(n>2),根据质数的定义,很容易想到遍历 [2,n-1] 看是否存在某个数可以整除它,如果存在则不是素数。// isPrime 判断某个数是否是素数func isPrime(n uint64) bool { if n <= 2 { retur原创 2020-12-04 19:40:50 · 1635 阅读 · 0 评论 -
哈希冲突常用解决方法
1.基本概念哈希算法:根据设定的哈希函数H(key)和处理冲突方法将一组关键字映象到一个有限的地址区间上的算法。也称为散列算法、杂凑算法。哈希表:数据经过哈希算法之后得到的集合。这样关键字和数据在集合中的位置存在一定的关系,可以根据这种关系快速查询。非哈希表:与哈希表相对应,集合中的数据和其存放位置没任何关联关系的集合。由此可见,哈希算法是一种特殊的算法,能将任意数据散列后映射到有限的空间上,通常计算机软件中用作快速查找或加密使用。哈希冲突:由于哈希算法被计算的数据是无限的,而计算后的结果范围有限原创 2020-11-08 23:20:02 · 16105 阅读 · 2 评论 -
图解红黑树
1.红黑树简介红黑树(Red Black Tree)是一种含有红黑结点并能自平衡二叉查找树,典型的用途是实现 map。它必须满足下面规则:规则1:每个结点要么是黑色,要么是红色。规则2:根结点是黑色。规则3:每个叶子结点(NIL)是黑色。规则4:每个红色结点的两个子结点都是黑色。规则5:任意一结点到每个叶子结点的路径都包含相同数量的黑结点。记住上面的规则也不难,我们会发现黑色结点非常特殊,规则1即“非红即黑”,规则2和3即“首尾全黑”,规则4即“红子双黑”,规则5即“路径等黑”。这些规则原创 2020-08-10 10:52:31 · 1932 阅读 · 5 评论 -
二叉树的构建
二叉树的前序、中序和后序序列中的任何一个都不能唯一确定一棵二叉树,二叉树的构建主要有两大种方法。第一种是根据前序+中序或者后序+中序来唯一确定二叉树的结构,第二种是根据二叉树对应的扩充二叉树的先序或者后序序列来确定。网上有很多blog和资料都没有将上面的方法列举出来,有个文档资料里说根据扩充二叉树的任意一个遍历序列就能唯一确定这棵二叉树。这个说法是错误的,这份文档见here。举一个反例即可证明根据扩充二叉树的中序遍历序列是不能唯一确定二叉树的结构,以文档中的描述为例:上图中扩展二叉树的中序遍历序列原创 2020-05-25 14:16:11 · 9848 阅读 · 4 评论 -
二叉树遍历(深度优先+广度优先)
二叉树的遍历分为两类,一类是深度优先遍历,一类是广度优先遍历。原创 2020-05-22 13:05:07 · 10311 阅读 · 1 评论 -
王小云院士真地破解了 MD5 吗
1.MD5简介MD5(Message-Digest Algorithm 5)是一种被广泛使用的消息摘要算法,也称为哈希算法、散列算法或杂凑算法,可以产生出一个定长的128位(16字节)的散列值(Hash Value),一般用于数字签名以确保信息传输完整性与密码的加密存储。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。2....原创 2019-02-27 00:08:23 · 35300 阅读 · 7 评论 -
统计无符号整数二进制中 1 的个数(Hamming Weight)
1.问题来源之所以来记录这个问题的解法,是因为在在线编程中经常遇到,比如编程之美和京东的校招笔试以及很多其他公司都累此不疲的出这个考题。看似简单的问题,背后却隐藏着很多精妙的解法。查找网上资料,才知道这个问题的正式的名字叫Hamming weight(汉明重量)。2.问题描述对于一个无符号整型数,求其二进制表示中1的个数。比如12的以32位无符号整型来表示,其二进制为:00000000 000000......原创 2016-11-24 11:07:38 · 5111 阅读 · 3 评论 -
Dijkstra 算法求单源最短路径
1.最短路径在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同。如果是一个带权图,那么路径长度为路径上各边的权值的总和。两个顶点间路径长度最短的那条路径称为两个顶点间的最短路径,其路径长度称为最短路径长度。最短路径在实际中有重要的应用价值。如用顶点表示城市,边表示两城市之间的道路,边上的权值表示两城市之间的距离。那么城市A到城市B连通的情况下,哪条路径距离最短呢,原创 2016-04-02 18:21:50 · 23681 阅读 · 2 评论 -
不用加号实现两整数相加
2.异或实现对于二进制的加法运算,若不考虑进位,则1+1=0,1+0=1,0+1=1,0+0=0,通过对比异或,不难发现,此方法与异或运算类似。因而排出进位,加法可用异或来实现。然后考虑进位,0+0进位为0,1+0进位为0,0+1进位为0,1+1进位为1,该操作与位运算的&操作相似。那么加法运算可以这样实现:(1)先不考虑进位,按位计算各位累加(用异或实现),得到值a;(2)然后再考虑进位,并将进位的值左移,得值b,若b为0,则a就是加法运算的结果,若b不为0,则a+b即得结果,此时可递归调用位运算函原创 2018-05-30 13:28:29 · 3873 阅读 · 2 评论 -
维诺图分析与实现
Voronoi 图的又叫泰森多边形或 Dirichlet 图,由两邻点连线的垂直平分线组成的连续多边形构成。每个V多边形内有一个生成元;每个V多边形内点到该生成元距离短于到其它生成元距离;多边形边界上的点到生成此边界的生成元距离相等;邻接图形的 Voronoi 多边形界线以原邻接界线作为子集。原创 2016-08-18 19:50:19 · 81630 阅读 · 26 评论 -
八皇后问题
1.问题描述八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 2.解法一2.1解题思路首先我们分析一下问题的解,我们每取出一个皇后,放入一行,共有八种不同的放法,然后再放第二个皇后,同样如果不考虑规则,还是有八种放法原创 2016-04-10 11:56:35 · 3284 阅读 · 0 评论 -
动态规划解决约瑟夫环问题
题目: 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号0,1,2,3…n-1分别表示)围坐在一张圆桌周围。从编号为0的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,求最后一个出列的人。1.经典解法可以用链表来模拟约瑟夫环,每次在链表中删除第m个节点,然后不断,直至链表中只剩下一个节点。最后一个这个节点就是我们要求的节点。 注意原创 2016-03-28 10:09:04 · 5417 阅读 · 1 评论 -
n 个骰子点数和及各自出现的概率
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率。这道算法题可采取动态规划法来求解。鉴于《剑指Offer》中对该题的解法晦涩难懂,尤其是代码,也没有指明其解题的思路本质上就是动态规划,所以提出自己的理解和答案。动态规划法简介: 动态规划法求解的总体过程就是将问题分为多个不同的阶段的问题,根据最开始阶段已知的问题的解逐步推导出最终解。即动态规划算法通原创 2016-03-26 22:06:57 · 16867 阅读 · 3 评论 -
给定入栈序列,判断出栈序列是否合法
题目:分别给定入栈序列和出栈序列,然后判断出栈序列是否合法。如入栈序列是[1,3,2,4,5],出栈序列[3,1,2,4,5]是合法的,[3,1,5,2,4]是不合法的。思路: 判断出栈序列是否合法的标准是:栈顶如果是需要出栈的元素,则出栈,如果不是则将未入栈的元素按入栈序列依次入栈,直到栈顶为出栈的元素。如果所有元素都入栈了,仍然没有找到要弹出的元素,那么该出栈序列一定不是合法的。参考原创 2016-03-25 19:25:48 · 4113 阅读 · 4 评论 -
判断二叉树是否为平衡二叉树
题目: 输入一颗二叉树的根节点,判断该树是不是平衡二叉树。1.平衡二叉树定义:一棵空树或它的任意节点的左右两个子树的高度差的绝对值均不超过1。下面就是一颗平衡二叉树: 2.解法一解题思路: 根据二叉树的定义,我们可以递归遍历二叉树的每一个节点来,求出每个节点的左右子树的高度,如果每个节点的左右子树的高度相差不超过1,按照定义,它就是一颗平衡二叉树。参考如下代码://求二叉树的高度int t原创 2016-04-07 15:31:23 · 10479 阅读 · 0 评论 -
打印1到最大的n位数
这道题是面试过可能会遇到的手写代码题。如n为3时,那么需要打印1到999。需要注意的是当输入的n很大时,最大的n位数是不能通过int或者long long int来表示,此时可以使用字符数组来存储。思路一: 1到n位最大数值采用字符数组存储。数值的高位存储在字符数组的低地址位。#include <string.h>#include <iostream>using namespace std;//原创 2016-03-25 12:50:30 · 1379 阅读 · 0 评论 -
数组中的逆序对
题目: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。解法一:暴力法 统计数组中的逆序对的逆序对,可以使用暴力的方法,即顺序扫描整个数组,每扫描到一个数字的时候,逐个与该数字后面的数字比较大小,如果大于后面的某个数字,则形成一个逆序对。暴力法简单易懂,容易实现,但是其时间复杂度为O(n2)O(n^2)。解法二:归并统计原创 2016-03-30 12:45:55 · 1696 阅读 · 0 评论 -
算法设计的方法
1.算法简介作用:要使计算机能完成人们预定的工作,首先必须为如何完成预定的工作设计一个算法,然后再根据算法编写程序。定义:简单的说,算法(Algorithm)是由有穷规则构成的为解决某一类问题的运算序列(方法或过程)。算法的性质:算法可以有若干输入,这些输入是在算法开始时给出的初始值或条件;算法通常又有若干输出,是对输入进行加工后的计算结果。另外算法的性质有: (1)有穷性。一个算法必须在执行了有原创 2016-03-01 21:57:31 · 5436 阅读 · 0 评论 -
常见排序算法分类
排序算法分为两大类: 比较类非线性时间排序:交换类排序(快速排序和冒泡排序)、插入类排序(简单插入排序和希尔排序)、选择类排序(简单选择排序和堆排序)、归并排序(二路归并排序和多路归并排序)。 非比较类线性时间排序:计数排序、基数排序、桶排序。 请记住:两类排序原创 2015-05-08 00:49:21 · 3078 阅读 · 0 评论 -
利用 OpenMP 实现埃拉托斯特尼(Eratosthenes)素数筛法并行化
1.算法简介1.1筛法起源筛法是一种简单检定素数的算法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛法(sieve of Eratosthenes)。原创 2015-05-09 12:24:23 · 5394 阅读 · 0 评论 -
归并排序及其并行化
归并排序是分治法(Divide and Conquer)的一个典型的应用,属于比较类非线性时间排序,比较类排序中性能最佳,应用较为广泛。归并排序先使每个子列有序,再将子列合并成有序列。若将两个子序列合并成一个有序列,称为二路归并。原创 2015-05-08 17:46:29 · 11400 阅读 · 2 评论