数据结构和算法
文章平均质量分 67
Owl丶
这个作者很懒,什么都没留下…
展开
-
数位DP:求区间中满足“某种条件”的数的总数
使用场景给定一个闭区间[L, R],求这个区间中满足"某种条件”的数的总数量。(Ans[L, R] = Ans[0, R] - Ans[0, L-1])例题Windy数(BZOJ1026)https://ac.nowcoder.com/acm/problem/20268定义不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。比如5, 36, 192都是Windy数, 10, 21不是Windy数。 求[L,R]范围内有多少个Windy数。 1<=L,R<=2e9思原创 2021-05-28 22:57:56 · 1529 阅读 · 0 评论 -
马踏棋盘 回溯/贪心
转自公众号:树屋编程直接用递归回溯很慢,可以通过加入贪心来加快计算速度:用贪心算法的思想来解决在棋盘如何选择下一个节点的问题,就是计算马儿的哪个下一节点对应的下一个节点(即下下个节点)的总数最少,就将哪个下一节点视为最优。(尽量选择出口最少的点,就能在最短时间内到达较深处,就能让计算速度尽量快)#include <bits/stdc++.h>using namespace std;// 每个点最多可以朝8个方向跳const int DIRECTIONS = 8;struct转载 2021-01-30 23:42:04 · 149 阅读 · 0 评论 -
有限状态机
转载自公众号:树屋编程在编程的时候,经常需要根据一个当前状态和各种可能的输入来实现不同的逻辑以及维护状态的变化,一般用if…else或者swith…case来实现,这其实就是状态机的思想。掌握一些关于状态机的理论知识和工具,能够更好更快地写出状态机的代码,尤其是当状态和输入较多的时候。本文从简单的例子开始,介绍状态机的一些知识,然后再介绍各种不同的C++实现。先来看一个非常简单的面试题怎么用状态机来实现:有一个ASCII字符串,其中包含数字和非数字,请找出其中所有的连续的数字.比如说对于字符串:ab转载 2020-12-20 20:25:04 · 3039 阅读 · 1 评论 -
求组合数 :DP、逆元+快速幂
要求:求 Cmn%pC_{m}^n \% pCmn%p ,p为素数(经典p=1e9+7)方法一:DPC[n][m]=CnmC_{n}^mCnm公式Cnm=Cn−1m−1+Cn−1mC_{n}^m=C_{n-1}^ {m-1}+C_{n-1}^{m}Cnm=Cn−1m−1+Cn−1m证明:班级中有n个人,选出m个人开除,有两种选法:班长不开除,从剩下的人中开除m个人开除班长,从剩下的人中开除m-1个人const int MOD = 1e9 + 7;int C[1005][1005原创 2020-08-30 16:02:28 · 295 阅读 · 1 评论 -
逆序对系列问题:求满足 i < j,且nums[j] -nums[i] < k 的( i , j )数量
LEETCODE中有一系列问题,思路都同逆序对:315.逆序对给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。493.翻转对给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。你需要返回给定数组中的重要翻转对的数量。327.区间和的个数给定一个整数数组 nums原创 2020-08-11 16:17:01 · 1480 阅读 · 0 评论 -
哈希冲突解决方法:开放寻址法、开链法、建域法
开放寻址法当哈希函数计算出的元素插入位置已不可用时,按某种规律探测其他可用位置的方法,叫开放寻址法。使用开放寻址法时,负载系数一定不超过1。探测方法有许多,开放寻址法 按探测方法的不同 又可以分为以下几种方法:线性探测最简单的探测方法:线性探测。线性探测有一个致命问题:平均插入成本的成长幅度,远高于负载系数的成长幅度。这样的现象在hashing过程中称为主集团(primary clustering)。此时的我们手上有的是一大团已被用过的方格,插入操作极有可能在主集团所形成的泥泞中奋力爬行,不断解原创 2020-08-09 16:25:32 · 2599 阅读 · 0 评论 -
区间DP
使用场景求一段区间的最优解,该区间的最优解可以由其子区间的最优解推导而来,类似分治思想。令状态f(i,j)表示将下标位置 i 到 j 的所有元素合并能获得的价值的最大值,那么f(i,j) = max{f(i,k) + f(k+1, j) + cost}, k∈[i+1,j-1] ,cost为合并代价特点合并:将两个或多个部分进行整合,或者将一个区间拆分成多个部分特征:能将问题分解为能两两合并的形式求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问转载 2020-08-09 13:55:35 · 144 阅读 · 1 评论 -
链表排序:快速排序、归并排序
快速排序非交换节点值【思路】链表快排与普通快排的不同首先在于链表无法直接swap,因此使用leetcode86题的双指针方法实现partition。其次,因为排序后首尾节点会变化,所以需要记录新的首节点。struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} ListNode(int x,ListNode* p) : val(x), next(p) {原创 2020-08-06 21:21:12 · 202 阅读 · 0 评论 -
并查集、Trie树模板
并查集int father[100010];void init(int n) { for (int i = 1; i <= n; i++) father[i] = i;}int get(int x) { return father[x] == x ? x : father[x] = get(father[x]); //路径压缩,防止链式结构}void merge(int x, int y) { father[get(x)] = get(y);}原创 2020-08-06 15:02:19 · 114 阅读 · 0 评论 -
unordered_map 自定义哈希
unordered_map定义template<class Key, class Ty, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>, class Alloc = std::allocator<std::pair<const Key, Ty> > > class unordered_map; > class unor转载 2020-08-04 09:26:11 · 7541 阅读 · 0 评论 -
线段树模板
使用场景O(n)时间初始化(建树),O(logn)时间内完成区间查询、区间(或单点)更新。主要解决区间动态 修改&查询 问题(查询区间最值、区间和……)。模板简约版不需要区间更新,最多单点更新,不需要lazy标记。求区间和:#include <bits/stdc++.h>using namespace std;const static int N = 100010; //数组大小typedef long long ll;ll A[N], tree[4 * N],原创 2020-08-02 22:50:36 · 126 阅读 · 0 评论 -
状态压缩动态规划(状压DP) 及 枚举子集优化
一个整数可以转化成二进制数,它可以代表某个集合的一个状态,这两者一一对应。使用场景如果一个题目适合用dp求解,但是状态特别多,可以把状态压缩为二进制数,使用状态压缩DP。整数的二进制表示状态,通过位运算进行状态转换。旅行商问题:有一个商人想要旅行各地并进行贸易。各地之间有若干条单向的通道相连,商人从一个地方出发,想要用最短的路程把所有地区环游一遍,请问环游需要的最短路程是多少?在这题当中,我们假设商人从0位置出发,最后依然回到位置0。#include<bits/stdc++.h>u原创 2020-07-29 14:37:03 · 1312 阅读 · 0 评论 -
已知 sqrt (2)约等于 1.414,要求不用数学库,求 sqrt (2)精确到小数点后 10 位。二分法、模拟退火算法
问题:已知 sqrt (2)约等于 1.414,要求不用数学库,求 sqrt (2)精确到小数点后 10 位。【方法一】二分查找double sqrt2( ){ double low = 1.4, high = 1.5; const double eps = 1e-11; while (high - low > eps){ double mid = (low + high) / 2; if (mid*mid > 2){ hi原创 2020-07-28 09:46:35 · 656 阅读 · 0 评论 -
LRU和LFU算法 C++实现
LRU【思路】哈希表+双向链表list使用节点为pair<int,int>的双向链表list,同时用存储对应节点迭代器的哈希表来实现O(1)查询。(用pair<int,int>来代替有key,value两成员的节点Node)因为从哈希表中删除尾结点时,需要知道尾结点对应的key,所以链表节点必须储存key。class LRUCache {private: int capacity; list<pair<int,int>> mylist原创 2020-07-16 16:44:40 · 700 阅读 · 0 评论 -
离散化
使用场景对于一个序列a,当数据范围很大,但是数据量很小,即数据在整个区间很稀疏。我们只关心这个序列中元素的相对大小,而不关心绝对大小(即只关心元素在序列中的排名)时,我们可以将原本分布零散的值聚集在一起,以减小数据范围。简而言之,将数组中元素改为该元素在整个数组中的排名,保持相对大小,减小数据范围。方法我们可以对原序列排序后去重,对于每一个 a[i] 通过二分查找的方式计算排名作为离散化之后的值。当然也可以不去重,不影响相对排名。void discretization(vector<in原创 2020-07-05 17:24:42 · 135 阅读 · 0 评论 -
树状数组
使用场景log(n)时间复杂度求动态数组(元素可变)区间和,准确的来说是前缀和,但区间和可以由两个前缀和相减来得到。log(n)时间复杂度对数组单个元素进行修改。定义原数组为a[1…n],定义数组t[1…n],t[k]表示从t[k]开始往左连续求 lowbit(k) 个数的和。lowbit(k)就是把k的二进制的高位1全部清空,只留下最低位的1,比如10的二进制是1010,则lowbit(k)=lowbit(1010)=0010(2进制),比较普遍实现的方法lowbit(k)=k&-k.原创 2020-07-05 15:59:54 · 127 阅读 · 0 评论 -
quickSelect C++
int partition(vector<int> &a,int l, int r){ swap(a[l],a[l+rand()%(r-l+1)]); int j=l,pivot=a[l]; for(int i=l+1;i<=r;i++){ if(a[i]<pivot){ swap(a[i],a[++j]); } } swap(a[l],a[j]); return j;}原创 2020-07-04 10:19:48 · 625 阅读 · 0 评论 -
构造哈夫曼树C++实现
定义给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。步骤求{11,8,6,5,2}构成的哈夫曼树的加权路径长度。【思路】永远让最小的两个数相加。1.用原始数组构造小顶堆,res=0;2.弹出堆顶两个最小值,和为sum,res+=sum;3.将sum放入堆中,如果堆内元素大于1则转到步骤2,否则转到下一步;4.堆中最后的树即为哈夫曼树的根原创 2020-07-02 16:46:04 · 1962 阅读 · 0 评论 -
KMP算法C++实现
next[j]含义:模式串P的子串[0,……,j-1]中,相匹配(相同)的真前后缀长度的最大值。真前后缀指是长度小于整个子串长度的前后缀,因为如果前后缀取整个子串,前后缀必相等,没有意义。N(P , j )={0<=t<=j-1 | P[0,t-1]=P[j-t , j-1] }next[j]=max( N(P,j) )初始值next[0]= - 1字符串匹配过程中。若在某一轮比对中首对字符就失陪,则应将P直接右移一个字符,然后启动下一轮匹配。不妨假象地在P[0]左侧“附加”一个P[原创 2020-06-27 09:42:22 · 170 阅读 · 0 评论 -
最小生成树算法:Prim算法和Kruskal算法
简介最小生成树处理的是无向图常用算法:Prim算法 O(n²)适合稠密图Kruskal(克鲁斯卡尔)算法O(mlogm)适合稀疏图Prim算法伪代码 dist[i] <- 正无穷 for (i=0; i < n; i++) // 迭代n次,加入n个点 t <- 找到集合外距离最近的点 \\s[t]为false,且dist[i]最小的点 用 t 更新其他点到集合的距离 s[t] = true时间复杂度:O.转载 2020-06-21 18:23:11 · 218 阅读 · 0 评论 -
最短路算法:Dijkstra算法、Bellman-Ford算法、spfa算法和Floyd算法
最短路算法的分类:单源最短路 所有边权都是正数 朴素的Dijkstra算法 O(n^2) 适合稠密图(n为节点个数) 堆优化版的Dijkstra算法 O((m+n)log n)(m是图中边的个数)适合稀疏图 存在负权边 Bellman-Ford O(nm) spfa 一般O(m),最坏O(nm)多源汇最短路 Floyd算法 O(n^3)【例题】【方法一】朴素Dijkstraclass Solution {publ原创 2020-06-19 15:32:59 · 1442 阅读 · 0 评论 -
二分查找/二分答案:最长上升子序列(LIS)、最大的最小值、最小的最大值
【总结】使用while(left<right)分析起来更清晰,且不会越界。但是,用left=mid收缩边界时(比如求右边界),mid必须向上取整:mid=(left+right+1)/2,否则在元素只有两个时进入死循环。【举例】nums={1,1} ,求1的右边界时,mid=(0+1)/2=0,while(left<right){ int mid=le...原创 2020-05-04 10:41:04 · 503 阅读 · 0 评论 -
快排平均复杂度O(nlogn)证明
直观证明1.划分点按照1:9划分时,用递归树分析时间复杂度:T(n)=T(n/10)+T(9n/10)+O(n)不难得出:对于任意划分只要是常数倍数的,不管是1:99,1:999,1:9999,只要不是1:(n-1) ,我们的时间复杂度都是O(nlogn)。2.在平均情况下,好的划分(常数比例划分)和坏的划分(1:n-1)是平均出现在划分树上的,当好、差划分交替在各层时,快排的运行时间就如...原创 2020-04-27 12:47:41 · 630 阅读 · 4 评论 -
快速排序优化算法 五种 c++
快排思想快排算法是基于分治策略的排序算法,其基本思想是,对于输入的数组a[low, high],按以下两个步骤进行排序:1)划分:以a[p]为基准将a[low: high]划分为三段a[low:p-1],a[p]和a[p+1:high],使得a[low:p-1]中任何一个元素小于等于a[p], 而a[p+1: high]中任何一个元素大于等于a[p]。2)递归求解:通过递归调用快速排序算法分...原创 2020-04-26 20:42:48 · 1452 阅读 · 0 评论 -
快速排序 的 尾递归优化 详细分析
传统快排递归函数void QSort(int arr[],int low,int high){ int pivotPos; if(low < high) { pivotPos = Partition(arr,low,high); QSort(arr,low,pivotPos-1); QSort(arr,pivotPos+1,high); }}尾递归详细介绍因...原创 2020-04-26 15:38:40 · 1787 阅读 · 0 评论 -
左神进阶班笔记Part6:前缀树应用、DP应用、约瑟夫链表
最大异或和【思路】利用异或运算性质O^N=N , N ^N=0,异或运算满足结合律、交换律。得出:[start , end]上的异或和 等于[0 , end] 上的异或和异或 [ 0 , start-1] 上的异或和。因此可以用dp表记录 [0 , i ] 上的异或和,线性规划。...转载 2020-04-20 15:31:25 · 197 阅读 · 0 评论 -
左神进阶班笔记Part5:树形DP、LRU、LFU、
【TIP】二叉树的题目,不是遍历就是改递归树形DP:在树上做动态规划,计算顺序一定是从子树到根节点,题目一:最大搜索二叉子树求整颗二叉树的最大搜索二叉子树逻辑:将整个题目转成以每个节点作为头的最大搜索二叉子树,最大的搜索二叉子树一定在其中。基本二叉树的题目都可以利用这样的思想进行求解。【思路】当前节点的最大搜索子树可能来自于左子树的某个子树,右子树的某个子树,左子树是搜索二叉树,...转载 2020-04-17 14:41:38 · 443 阅读 · 3 评论 -
左神进阶班笔记Part4:BBST、累加和为定值最长子数组问题
文章目录平衡搜索二叉树BBSTAVL树红黑树应用SB树例题累加和为定值的最长数组平衡搜索二叉树BBSTAVL树任何一个节点的左子树和右子树高度差不大于1,复杂度还是O(logN)。导致调整非常频繁。红黑树每个节点染上色,头和叶节点必然黑,相邻两个节点不能出现连续的红节点,任何一条从根到叶节点的路径上黑节点数相等。所以最长链和最短链的高度差不超过1倍。应用C++中map底层使用的就是红...原创 2020-04-16 20:46:24 · 377 阅读 · 0 评论 -
莫里斯遍历
文章目录使用场景算法流程对比及本质三种遍历使用场景遍历二叉树,要求时间复杂度O(n),空间复杂度O(1)。【思路】常规的栈结构遍历方式,遍历到某个节点之后并不能直接回到上层的结点,因此需要使用栈来完成回到上层结点的步骤。Morris遍历避免了使用栈结构,让下层有指向上层的指针,但并不是所有的下层结点都有指向上层的指针([这些指针也称为空闲指针])。算法流程当前节点记为cur,如果c...原创 2020-04-15 21:29:24 · 1361 阅读 · 0 评论 -
左神算法进阶班笔记Part2:单调栈
文章目录单调栈使用场景例题构造数组的MaxTree柱状图最大矩阵面积最大矩阵面积环形山烽火传递单调栈使用场景单调栈解决的问题是:【单调递减栈】对于一个数组中每一个数,求左边离他近的比他大的和右边离他近的比他大的数;【单调递增栈】对于一个数组中每一个数,求左边离他近的比他小的和右边离他近的比他小的数。同时时间复杂度O(n),单调减栈栈底到栈顶单调递减,从大到小,递增相反。【分析】只分析...原创 2020-04-15 17:55:37 · 530 阅读 · 0 评论 -
左神算法进阶班笔记Part1:KMP、Manacher、BFPRT、窗口滑动问题
文章目录KMP算法最大回文子串Manacher算法KMP算法1.KMP详细2.相关题目1、【京东】给定一个字符串,要求在后面添加长度最短的字符,生成一个新的字符串,包含两个原始字符串。【思路】将字符串最长前后缀匹配长度算出后,next数组再多求一位,即可得到一个最长前缀、最长后缀。然后第二个字符串只需要将前缀和原始字符串的后缀重合,补充完整即可。2.判断树B是不是树A的某一子树【思路...原创 2020-04-13 15:49:44 · 580 阅读 · 0 评论 -
左神算法课PART3:图、BFS、DFS、拓扑排序、最小生成树、异或运算
lesson 8图前期准备class Edge;class Node{public: int value; int in; int out; list<Node*> next; list<Edge*> edges; Node(int value){ this->value = value; in = 0; out =0; }};...原创 2020-04-12 21:11:59 · 553 阅读 · 2 评论 -
左神算法课程笔记PART2:哈希、布隆过滤器、一致性哈希、并查集、前缀树、贪心、递归和动态规划
1原创 2020-04-10 19:38:13 · 547 阅读 · 0 评论 -
八大排序 C++版本
void merge(vector<int> &arr,int L,int mid,int R) //[L,R]闭区间{ vector<int> help(R-L+1); int p1=L,p2=mid+1,i=0; while(p1<=mid && p2<=R) help[i++] = arr[p1] < arr[p2...原创 2020-04-08 09:55:01 · 178 阅读 · 0 评论 -
左神算法课程笔记PART1:二分、排序、栈、队列、矩阵、链表、二叉树
文章目录初级班lesson1初级班lesson11.对数器:https://blog.csdn.net/weixin_39953502/article/details/795048792.master公式:3.TIP关于取中间值为什么为l+(r-l)/2,而不是(l+r)/24.归并排序思想:小范围有序在合并为大范围有序时,不会浪费小范围内已经进行过的的比较,因为小范围内已经有序。...原创 2020-04-07 22:42:27 · 282 阅读 · 0 评论 -
二叉树四种遍历(迭代、递归)
题目来自leetcode:前序:https://leetcode.com/problems/binary-tree-preorder-traversal/?tab=Description中序:https://leetcode.com/problems/binary-tree-inorder-traversal/?tab=Description后序:https://leetcode.com/p...原创 2020-04-04 19:10:39 · 385 阅读 · 0 评论 -
Bellman-Ford 算法证明 问题记录
Q:为什么第i次循环对w(v(i-1),vi)进行松弛操作才有用?A:因为在上一次循环中,w(v(i-1),vi)松弛操作可能发生在d[v(i-1)]=δ(s,v(i-1))成立之前。第i次循环的松弛操作必发生在d[v(i-1)]=δ(s,v(i-1))之后。完整证明出处:https://blog.csdn.net/rye_whiskey/article/details/82190906...原创 2020-03-30 16:32:16 · 345 阅读 · 0 评论 -
O(logn)时间复杂度求 x^n 和 斐波那契数列(分治法)
x^n算法分析:分而治之:x ^ n = x^(n/2) *x(n/2) ( n是偶数)x^ n = x^((n-1)/2) *x ^((n-1)/2) *x (n是奇数)如果 n == 1 ,则直接返回 x时间复杂度分析:T(n) = T(n/2)+O(1) (此处原来是2*T(n/2)+O(1) ,但是只需要计算一次)根据***...原创 2020-03-22 18:53:32 · 1426 阅读 · 0 评论 -
分治法时间复杂度求解:主定理、代换法和递归树
转自:https://www.cnblogs.com/qbits/p/10939541.html转载 2020-03-22 20:07:09 · 3472 阅读 · 2 评论 -
全域哈希和完全哈希
全域哈希:解决普通哈希的缺点: 对任意的hash函数h,总存在一组keys,使得对某个槽i总可以找到一组键值,让他们都映射到同一个槽里面,这样效率就跟离链表差不多了。解决的思想就是:(加入随机性)独立于键值,随机的选择hash 函数。这就跟快排中为避免最差情况时随机化版本差不多。但hash函数类有指定的特点:对于任意的不相等key的x和y, 从哈希函数集中选择一个哈希函数,这两个key,发...转载 2020-03-25 13:41:48 · 490 阅读 · 0 评论