数据结构与算法
harkecho
这个作者很懒,什么都没留下…
展开
-
堆排序代码
堆排序的基本三步走:1、将无序序列构造为堆结构,如果是升序排序则为 大顶堆,降序则为 小顶堆。(这里使用大顶堆)2、将 堆顶元素 与 堆尾元素进行交换(即,把当前最大元素 “沉” 入到 堆尾)3、重新构造堆结构,构造堆结构的目的就是将未排序序列的最大值 “抬” 到堆顶。(但是要注意,此时我们已经把一个最大值成功排序到堆尾了,因此我们应当排除掉已经排序好的元素。 我们可以用 len 来表示当前序列还未排序的序列长度,每次交换完 堆顶 和 堆尾 元素后 len–,然后重新构造堆结构时,如果当前元素下标大.原创 2020-08-17 15:18:13 · 187 阅读 · 0 评论 -
二分查找,寻找左侧边界,寻找右侧边界
这个场景是最简单的,肯能也是大家最熟悉的,即搜索一个数,如果存在,返回其索引,否则返回 -1int binarySearch(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left)/2; if (nums[mid] == target) { return mid; }else if (num.原创 2020-08-16 17:09:07 · 872 阅读 · 0 评论 -
训练营算法题
数组,链表,跳表:参考链接Java 源码分析(ArrayList)Linked List 的标准实现代码Linked List 示例代码Java 源码分析(LinkedList)LRU Cache - Linked list: LRU 缓存机制* Redis - Skip List:跳跃表、为啥 Redis 使用跳表(Skip List)而不是使用 Red-Black?Array 实战题目两数之和(近半年内,字节跳动在面试中考查此题达到 152 次)盛最多水的容器(腾讯、百度、字节跳动原创 2020-08-12 08:32:03 · 424 阅读 · 0 评论 -
2020-08-10
387. 字符串中的第一个唯一字符剑指 Offer 50. 第一个只出现一次的字符给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。示例:s = “leetcode” 返回 0s = “loveleetcode” 返回 2 func firstUniqChar(_ s: String) -> Character { var table: [Character: Int] = [:] for c i原创 2020-08-10 09:41:49 · 128 阅读 · 0 评论 -
高级字符串算法
72. 编辑距离给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。你可以对一个单词进行如下三种操作:插入一个字符删除一个字符替换一个字符示例 1:输入:word1 = “horse”, word2 = “ros”输出:3解释:horse -> rorse (将 ‘h’ 替换为 ‘r’)rorse -> rose (删除 ‘r’)rose -> ros (删除 ‘e’)示例 2:输入:word1 = “原创 2020-08-06 07:14:25 · 248 阅读 · 0 评论 -
字符串基础知识和引申题目
Python 中字符串 x = 'abbc’和Java中的String x = “abbc” 是imutable的,好处是线程安全的也就是说当将其加一个字符或者减一个字符其实都是新生成了一个String,原来的String还是原来的内容C++的话,字符串它是可变的在多线程环境string immutable遍历字符串for ch in "abbc": print(ch)String x = "abbc";for (int i = 0; i < x.size(); ++i) { .原创 2020-08-05 07:02:14 · 187 阅读 · 0 评论 -
高级动态规划
高级DP为什么复杂,第一:状态定义第二:状态转移方程它的复杂度来源于什么地方1 状态拥有更多维度(二维,三维,或者更多,甚至需要压缩(比如斐波那契只需要两个变量))每个维度是什么,逻辑清晰2 状态转移方程...原创 2020-08-05 04:58:05 · 195 阅读 · 0 评论 -
特殊排序
十大经典排序算法9 种经典排序算法可视化动画特殊排序 - O(n)• 计数排序(Counting Sort)计数排序要求输入的数据必须是有确定范围的整数。将输入的数据值转化为键存储在额外开辟的数组空间中;然后依次把计数大于 1 的填充回原数组• 桶排序(Bucket Sort)桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。• 基数排序(Radix Sort原创 2020-07-29 22:04:10 · 425 阅读 · 0 评论 -
初级排序和高级排序
十大经典排序算法(动图演示)比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序初级排序 - O(n^2)选择排序(Selection Sort)每次找最小值,然后放到待排序数组的起始位置。function selectionSort(arr) { var len = arr.l.原创 2020-07-28 21:22:20 · 270 阅读 · 0 评论 -
LRU Cache的实现,应用和题解
CPU Socket中Cache的理解LRU Cache 最近最少使用的缓存放在淘汰的位置两个要点: 大小,替换策略实现: Hash Table + Double LinkedList复杂度: O(1)查询, O(1)修改,更新LRU cache工作示例替换策略:LFU - least frequently used 统计每个元素使用到的频次最少LRU - least recently used替换算法LRU Cache面试题 16.25. LRU缓存146. LRU缓存机制#原创 2020-07-28 09:07:25 · 177 阅读 · 0 评论 -
布隆过滤器实现及应用
布隆过滤器 BloomFilter上图为哈希表:哈希表如果有重复元素采用拉链存储法,本身任何一个字符串进来经过一个哈希函数映射到整数下标位置index,比如 Lisa Smith映射到001,就存在001这个位置,她的电话是521-8976, Johe Smith和Sandra Dee都被哈希到152的位置,采用的冲突办法就是在152位置开一个链表,将多个元素存在相同位置的链表处,对于哈希表不仅有哈希函数得到这么一个index值,且会把整个要存的元素,全部放在哈希表中,这是个没有误差的数据结构,有多少个元原创 2020-07-28 08:25:55 · 282 阅读 · 0 评论 -
位运算基础及实战要点
如何从十进制转换为二进制位运算符左移 << 譬如 0011 => 0110右移 >> 譬如 0110 => 0011这里作为演示用4个二进制位,在计算机中老式计算机是32位,新计算机基本都是64位按位或 |按位与 &按位取反 ~按位异或(相同为0不同为1) ^XOR-异或 :相同为0, 不同为1. 也可用"不进位加法"来理解异或操作的特点:x ^ 0 = x // x和0相同为原创 2020-07-27 21:44:39 · 251 阅读 · 0 评论 -
启发式搜索的实现,特性
启发式搜索Heuristic Search(A*算法)基于BFS代码def BFS(graph, start, end): queue =[] queue.append([start]) while queue: node = queue.pop() # can we add more intelligence here? visited.add(node) process(node) nodes = generate_related_nodes(node) queue.pu原创 2020-07-27 06:33:18 · 877 阅读 · 0 评论 -
双向BFS的实现
Breadth First Search(BFS)下面是一个简单的双向连通图,从A一直要走到L,请问最短可以走多少路双向扩散,即从A向右扩散,也从L向左边扩散,当扩散的两层结点有重合的时候,第一次重合的地方就是A和L两者之间的最短路径,把左边扩散的步数加上右边扩散的步数,和就是最后 的总的步数127 单词接龙给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:每次转换只能改变一个字母。转原创 2020-07-26 22:35:10 · 198 阅读 · 0 评论 -
剪枝的实现和特性
初级搜索朴素搜索(暴力搜索,傻搜)优化方式:不重复(fibonacci),剪枝(生成括号问题)搜索方向: DFS(depth first search深度优先搜索,利用栈), BFS(breath first search,广度优先搜索,利用队列)高级搜索双向搜索:从起点和终点分别做一个广度优先,然后在中间相遇,时间更快些启发式搜索(优先级搜索,A*算法):不再用栈或者队列,这种先入先出或者先入后出的形式,而是用优先队列,节点按照优先级高级搜索剪枝比如零钱置换的状态树,进行状态树搜索原创 2020-07-26 14:30:04 · 206 阅读 · 0 评论 -
DFS, BFS代码模板
DFS代码模板递归写法// Javapublic List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> allResults = new ArrayList<>(); if (root == null) { return allResults; } travel(root, 0, results);}public void travel(Tre原创 2020-07-26 06:27:10 · 210 阅读 · 0 评论 -
字典树和并查集
字典树Trie字典树的数据结构字典树,即Trie树,又称单词查找树或键树,是一种树型结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计优点:最大限度地减少无谓字符串比较,查询效率比哈希表高字典树的基本性质结点本身不存完整单词从根节点到某一结点,路径上经过的字符连接起来,为该结点对应的字符串每个结点的所有子结点代表的字符都不相同结点存储额外信息. 下图中的数字表示单词的统计频次,然后给用户做相应的推荐(很多时候统计单词的频次,就会加一个原创 2020-07-21 08:40:53 · 200 阅读 · 0 评论 -
分治, 回溯 Pow(x, n)与子集与电话号码的字母组合
(Divide & Conquer)分治和回溯本质上就是特殊的递归, 找重复性 重复性有最近重复项(分治,回溯),和最优重复项(动态规划);不论分治,递归,回溯本质都是找重复性, 分解问题, 最后组合每个子问题的结果.将一个字符串转为大写字符串Python 递归代码模板def recursion(level, param1, param2, ...): #recursion terminator if level > MAX_LEVEL: process_result re原创 2020-06-26 07:01:08 · 290 阅读 · 0 评论 -
递归
递归树的面试题解法一般都是递归1 节点的定义(树的节点和树本身数据结构的定义就是用递归方式进行的)2 重复性(不仅树本身,二叉树以及搜索二叉树,比如二叉搜索树,它的左子树都要小于根节点,右子树都要大于根节点,且左右子树具有相同的特征)def preorder(self, root):if root: self.traverse_path.append(root.val) self.preorder(root.left) self.preorder(root.right)def ino原创 2020-07-14 07:14:24 · 164 阅读 · 0 评论 -
动态规划笔记
动态规划的本质就是将一个复杂的问题,分解成重复性子问题.分治,回溯,递归,动态规划,只是一些小的细节问题递归模板public void recur(int level, int param) {// terminator if (level > MAX_VALUE) { // process result return }// handle curr level logincprocess(level, param)// drill downrecur(level: l.原创 2020-07-12 15:50:38 · 119 阅读 · 0 评论 -
快排 两种不同方法(java + swift)
java语言 方法一public static void main(String[] args) { int[] array = {2, 4, 1, 20, 0}; mhfQuickSort(0,array.length,array); for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } } public s原创 2020-07-09 10:27:09 · 130 阅读 · 0 评论 -
位运算判断两个数是否异号
首先介绍下负数在计算机中的表示和存储在计算机系统中,数值一律用补码表示和存储。含符号位和数值位,符号位:0表示“正”; 1表示“负”。正数的补码 = 原码负数的补码 = 负数的原码取反(符号位保持不变)+ 1列如比如 -7 补=11111001(八位二进制) :原码:(符号位不变) 10000111反码:(符号位不变) 11111000(符号位不变)加1得补码:11111001为什么要使用补码的形式呢?例如在减法运算中,可以看作是正数和负数的加法操作,使用补码的形式表示数值原创 2020-07-08 06:36:57 · 3488 阅读 · 0 评论 -
按位或与加法的区别
0 | 0 = 0 1 | 1 = 1 0 | 1 = 1 1 | 0 = 10 ^ 0 = 0 1 ^ 1 = 0 0 ^ 1 = 1 1 ^ 0 = 10 & 0 = 0 1 & 1 = 1 0 & 1 = 0 1 & 0 = 00 + 0 =00 1 + 1 =10 0 + 1 =01 1 + 0 =01结论:1位二进制运算的低位就是异或运算的结果,进位就是与运算的结果。而如果加原创 2020-07-08 06:18:54 · 2466 阅读 · 0 评论 -
按位与& 和 模运算 % 的关系
unsigned int MAX = 32; // 2的5次方 unsigned int index = 31; index = (index + 100) % MAX; printf ("index = %d\n", index); // index = 3 index = 31; index = (index + 100) & (MAX - 1); printf ("index = %d\n", index); // ...原创 2020-07-08 05:38:07 · 345 阅读 · 0 评论 -
已理解的题
关于树的深度优先搜索算法描述错误的是A : 按照某个条件往前试探搜索,如果前进中遭遇失败, 则退回头另选通路继续搜索,直到找到条件目标为止B: 先访问该节点所有的子节点, 遍历完毕后选取它未访问过的子节点重复上述过程,直到找到条件目标为止C: 假设树的顶点树为V,则算法的空间复杂度为O(V)D: 深度优先算法非常适合使用递归来实现对于C选项来说,我不是太理解,因为DFS,空间复杂度就是树递归的深度, 那么就是logH,除非是树退化为链表的情况才是空间复杂度为O(V)啊,因为DFS,空间复杂度就是原创 2020-07-07 16:06:39 · 1143 阅读 · 0 评论 -
冒泡排序, 选择排序, 插入排序(c + swift)
C语言这里自己写错了 注意一下a = a^b;b = a^b;a = a^b;或者a ^= b;b ^= a;a ^= b;void mhfPrint(int array[], int len) { for (int i = 0; i < len; i++) { printf("%d ", array[i]); } printf("\n");}void mhfSwap(int array[], int i, int j) {原创 2020-07-06 17:52:31 · 117 阅读 · 0 评论 -
二分查找框架
int binarySearch(int[] nums, int target) { int left = 0, right = ...; while (...) { int mid = left + (right - left) / 2; if (nums[mid] == target) { ... }else if (nums[mid] < target) { left = ... }else if (nums[mid] > target) { righ原创 2020-07-03 15:00:07 · 176 阅读 · 0 评论 -
贪心算法Greedy笔记与应用
贪心算法是一种在每一步选择中都采用在当前状态下最好或最优(即最有利)的选择, 从而希望导致结果是全局最好或者最优的算法.(用贪心算法,尤其是最基础的贪心,每次当下情况下找到最优不一定能够达到全局最优的情况)贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退.动态规划会保存以前的运算结果, 并根据以前的结果对当前进行选择, 有回退功能.对比:贪心: 当下做局部最优判断回溯: 能够回退动态规划: 最优判断 + 回退 (带最优判断的回溯,我们叫做动态规划,动态规划会保存以前的运算原创 2020-07-01 06:50:52 · 354 阅读 · 0 评论 -
平方根(二分查找)
二分查找的前提(二分查找必须有序,如果是无序的话,无法进行二分查找)1 目标函数单调性(单调递增或者递减)2 存在上下界(bounded)3 能够通过索引访问(index accessible)查找过程列子思想:从左右不断往中间夹逼,这个过程又由于数组本身单调递增,所以我们可以每次排除一半实战 69. x 的平方根方法一: 二分查找/*实现 int sqrt(int x) 函数。计算并返回 x 的平方根,其中 x 是非负整数。由于返回类型是整数,结果只保留整数的部分,小数部分将被舍原创 2020-06-29 15:42:37 · 824 阅读 · 0 评论 -
TodoList 每日一题 正则表达式匹配
每日一题 正则表达式匹配 比较有代表性的分治+DP先简化题目, 第一个版本考虑.和*bool isMatch(string s, string p) { if (p.empty()) return s.empty(); bool firstMatch = !s.empty() && s[0] == p[0]; return firstMatch && isMatch(s.substr(1), p.substr(1));}然后考虑 . 的情况: boo原创 2020-06-20 19:00:07 · 170 阅读 · 0 评论 -
二叉树的深度优先遍历(DFS)与广度优先遍历(BFS)
二叉树的深度优先遍历(DFS)与广度优先遍历(BFS)深度优先遍历:从根节点出发, 沿着左子树的方向进行纵向遍历,直到找到叶子节点为之, 然后回溯到前一个节点, 进行右子树节点的遍历,直到遍历完所有可达节点为止广度优先遍历: 从根节点出发,在横向遍历二叉树层段节点的基础上纵向遍历二叉树层次 A B C D E F G DFS:原创 2020-06-20 17:37:43 · 402 阅读 · 1 评论 -
堆的实现代码
import java.util.Arrays;import java.util.NoSuchElementException;public class BinaryHeap { private static final int d = 2; private int[] heap; private int heapSize; /** * This will initialize our heap with default size. */原创 2020-06-18 05:27:54 · 101 阅读 · 0 评论 -
堆和二叉堆的实现和特性
二叉堆:通过完全二叉树(不是二叉搜索树)完全二叉树就是它的根和每一级节点都是满的,除了最小面一层的叶子可能不满用二叉搜索树也可以实现堆(也可以,但是慢了,二叉搜索树,整体是有序的,可以找最小值,也可以找最大值,同时增加删除也是LogN,但是二叉搜索树找最小值就不是O(1)的就变成LogN了,因为要遍历这个树,找到最左边的叶子节点)二叉堆(大顶)满足性质1 是一颗完全树2 树种任意节点的值总是 >= 其子节点的值 (保证根节点就是最大的值二叉堆实现细节(二叉堆通过数组实现)假设”第一个元素原创 2020-06-15 07:05:09 · 224 阅读 · 0 评论 -
二叉树前序,后序,中序遍历以及验证二叉树
二叉树前序遍历public List<Integer> preorderTraversal(TreeNode root) { LinkedList<TreeNode> stack = new LinkedList<>(); LinkedList<Integer> output = new LinkedList<>(); if (root == null) {return output;} stack.add(root); while原创 2020-06-13 08:07:42 · 216 阅读 · 0 评论 -
空间复杂度问题
为什么同样都是用递归, 有的空间复杂度是O(logn),有的是O(N)呢,我是这么理解的,可能不对,大家给指导下,如果是递归中的参数+1或者-1这种的,因为递归要占用栈空间,所以空间复杂度为O(n),如果是一半一半的递归,因为每次减半深度只有logn所以是O(logn),使用栈空间的深度是多少,空间复杂度就是多少么?比如有的时候,如果递归太深,程序崩溃,是因为占用栈的空间太多,没能释放引起的么,这里是方法栈没能释放么,如果我理解的不对,那么我们所说的递归开辟栈空间所以空间复杂度为O(n)怎么理解呢?答案原创 2020-06-11 09:11:00 · 269 阅读 · 0 评论 -
刻意练习
递归特性树的面试题解法一般都是递归1 节点的定义2 重复性(自相似性二叉搜索树:左子树小于根节点,右子树大于根节点, 且左右子树具有相似特征 (中序遍历为升序)def inorder(self, root):if root: self.inorder(root.left) self.traverse_path.append(root.val) self.inorder(root.right)List<Integer> list = new ArrayList<&g原创 2020-06-10 07:35:50 · 211 阅读 · 0 评论 -
树,二叉树,二叉搜索树算法课程总结:
树的由来由单链表最大问题查询太慢O(n)引出跳表(更快的索引),再想到的思想,就是加速,加速的关键在于升维,那么二维数据结构常见的树,图, 树的出现如果在单链表的next有多个的话,就变成了树树(根节点,左子树,右子树),现实生活用的是二叉树比较多,树跟图最关键的差别是有无环,如果节点只连到新的儿子节点就是树,如果节点会与兄弟节点和曾祖父节点连接就是图******Lisked List是特殊化的Tree,因为有两个Next指针******Tree是特殊化的Graph(节点只连到新的儿子节点)树节原创 2020-06-09 16:02:04 · 176 阅读 · 0 评论 -
数据结构与算法总览
精通一个领域chunk it up 切碎知识点切成一块一块,且脉搏相邻![在这里插入图片描述](https://img-blog.csdnimg.cn/20200609055150958.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI1ODE3NjA=,size_16,color_FFFFFF,t_70)引用一个在几个领域中都做的原创 2020-06-09 06:25:16 · 123 阅读 · 0 评论 -
递归条件分析时间复杂度
递归总共执行了这个语句多少次递归执行顺序画成树形结构,我们称之为递归树求Fibonacci数列的第n项Fib: 0, 1, 1, 2, 3, 5, 8, 13 …F(n) = F(n - 1) + F(n - 2);// 面试,直接用递归int fib(int n) { if (n < 2) return n; return fib(n - 1) + fib(n - 2);}这段语句的时间复杂度分析/*要计算fib(6)因为6不小于2,所以就要计算fib(5) + fib(原创 2020-06-08 19:40:45 · 268 阅读 · 0 评论 -
归并排序时间复杂度分析
// 归并public void static main() { int num = 10; int array = new int[10]; for(int i = 0; i < num; i++){ array[i] = Math.random() * 100; } int leftArray = new int[num >> 2];}public void static sort(int begin, int end, int[] array, int[]原创 2020-06-08 17:17:51 · 8334 阅读 · 0 评论