自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(33)
  • 收藏
  • 关注

原创 64位整数乘法

位运算解决64位整数乘法假设a和b都是64位整数,要计算a*b同样可以利用位运算,首先还是考虑把b通过二进制的思想分解成几个数的和,b=n1+n2+...+nkb=n_{1}+n_{2}+...+n_{k}b=n1​+n2​+...+nk​,要注意这k个数之间的关系,那么a∗ba*ba∗b就可以写成a∗n1+a∗n2+...+a∗nka*n_{1}+a*n_{2}+...+a*n_{k}a∗n1​+a∗n2​+...+a∗nk​.所以还是每次判断b的最低位,看是否为1,比如第i位为1,就加2i2^{i}2

2022-03-24 20:14:10 1108 1

原创 位运算求a^b

给定一个题目,求a^b mod p,如果用暴力(循环)去求可能会导致超时,我们可以考虑使用快速幂算法,可以很快的求出结果。算法其实来自一句初中数学的定理,同底数幂相乘,底数不变,指数相加。所以我们可以将b写成几个数相加的形式,但要怎么写呢,没错,用二进制。比如11的二进制可以写成1011(8+2+1),所以a11a^{11}a11可以写成a8∗a^{8}*a8∗ a2∗a^{2}*a2∗ a1a^{1}a1,用二进制还有一个好处就是方便使用位运算。每次判断b的最低位是否为1,是则要乘以一个a的幂,否则不需要

2022-03-24 19:35:59 225

原创 线性回归的从零开始实现

根据带有噪声的线性模型构造一个人造数据集,生产1000个样本的数据集,噪声服从均值为0的正态分布torch.normal()返回一个张量,张量里面的随机数是从相互独立的正态分布中随机生成的。画散点图要引入的包import matplotlib.pyplot as pltbackward()函数实现反向传播求导,可用于自动求导...

2021-12-25 14:22:39 794

原创 线性神经网络

名词解释::训练集:搜集的一个真实数据集,用于训练;样本:训练集中的每行数据;标签(目标):试图预测的东西;特征:预测所依据的自变量。对于一个线性假设的式子:y=ω1x1+ω2x2+by=\omega_{1}x_{1}+\omega_{2}x_{2}+by=ω1​x1​+ω2​x2​+b,其中ω1\omega_{1}ω1​和ω2\omega_{2}ω2​为权重,bbb为偏置,给定一个数据集,我们的目标就是寻找模型的权重和偏置。一种模型质量的度量方式:平方误差损失函数,当样本iii的预测值为y^(i)\.

2021-12-22 17:45:21 519

原创 预备知识(二)

对于一个矩阵A,可以使用A.T对矩阵A进行转置图像以n维数组的形式出现,其中3个轴对应于高度、宽度以及一个通道轴,用于堆叠颜色通道将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘指定axis=0降维求和相当于把每一列相加求和,指定axis=1降维求和相当于把每一行相加求和点积(xTy\textbf{x}^{T}\textbf{y}xTy或<x,y\textbf{x,y}x,y>)是两个向量相同位置的按元素乘积的和,调用.dot()函数可以实现点积的计算.

2021-12-21 17:17:47 89

原创 预备知识(一)

n维数组,也叫张量PyTorch中的tensor和Numpy中的ndarry类似,但功能更强大张量表示有数值组成的数组,可以有多个维度,一维对应数学上的向量,二维对应数学上的矩阵使用arange可以创建行向量可以通过shape属性访问张量的形状(.shape),调用reshape函数改变张量的形状torch.zeros((2,3,4))表示创建一个形状为(2,3,4)的张量,所有元素都置为0,torch.randn(3,4)表示创建一个形状为(3,4)的张量,每个元素服从均值为0,标准差为1的标.

2021-12-20 17:28:43 439

原创 机器学习笔记

1、在神经网络中常用的激活函数有sigmoid函数和tanh函数。sigmoid(x)=11+e−xsigmoid(x)=\frac {1}{1+e^{-x}}sigmoid(x)=1+e−x1​tanh(x)=ex−e−xex+e−xtanh(x)=\frac {e^x- e^{-x}}{e^x + e^{-x}}tanh(x)=ex+e−xex−e−x​

2021-10-13 08:34:58 71

原创 求组合数II

求组合数II前一篇文章求组合数I一切讨论都在模ppp意义下,中数据范围是1−20001-20001−2000,这里增加到10510^5105,在用前面的方法就会超时了,那么我们怎么做呢,我们看一下CabC_a^bCab​的表达式,Cab=a!b!∗(a−b)!C_a^b=\frac {a!}{b!*(a-b)!}Cab​=b!∗(a−b)!a!​,因为我们每次的结果很大,都是要对1e9+71e9+71e9+7取模,而ab mod p=a∗b−1 mod p\frac

2021-08-20 17:20:02 95

原创 求组合数I

求组合数给定两个数a,ba,ba,b,求CabC_a^bCab​mod(1e9+7)mod(1e9+7)mod(1e9+7),这里a,ba,ba,b的范围是1≤ b≤ a≤ 20001\leq\ b\leq\ a\leq\ 20001≤ b≤ a≤ 2000。这里只需要用到一个简单的组合数公式进行递推就行了。公式就是Cab=Ca−1b+Ca−1b−1C_a^b=C_{a-1}^b+C_{a-1}^{b-1}Cab​=Ca−1b​+Ca−1b−1​

2021-08-20 16:46:38 118

原创 快速幂求逆元

快速幂求逆元我们首先看一下乘法逆元的定义,若整数 b,mb,mb,m 互质,并且对于任意的整数 aaa,如果满足 b∣ab|ab∣a,则存在一个整数xxx,使得 ab\frac {a}{b}ba​≡a×x(mod m)a×x(mod\ m)a×x(mod m),则称 xxx 为 bbb 的模 mmm 乘法逆元,记为 b−1(mod m)b^{−1}(mod\ m)b−1(mod m)。bbb 存在乘法逆元的充要条件是 bbb 与模数 mmm 互质。当模数 mmm

2021-08-20 16:32:37 685

原创 快速幂算法

快速幂给定n组ai,ki,pia_i,k_i,p_iai​,ki​,pi​,对于每组数据,求出aikia_i^{k_i}aiki​​modpip_ipi​。我们的快速幂算法是这样子的,首先我考虑将kkk写成二进制的形式,那么这个表示形式一定是可以的,而且是唯一的。那么这样一来假设kkk=2b1+2b2+...+2bn2^{b_1} + 2^{b_2} + ... + 2^{b_n}2b1​+2b2​+...+2bn​,那么aka^kak就可以写成a2b1+2b2+...+2bna^{2^{b_1} + 2

2021-08-20 15:59:29 132

原创 筛法求素数

筛质数给出一个整数n,计算1~n中质数的个数,筛质数的方法大概有这么三种,朴素筛法,埃式筛法以及线性筛法。这三种方法都需要两个数组,一个整数类型,一个布尔类型,整数类型的数组primes用于存储素数,布尔类型的数组s用于标记是否被筛去。朴筛从i=2到n枚举,对于每个没被标记的数i,说明是素数,记录下来,同时对于i的倍数,从i的2倍开始枚举,直到n,这些数都要标记一下,因为这些数肯定是合数。这种方法的弊端在于很多数要被筛多次,造成了时间上的浪费,接下来看一下代码:int is_prime(int n

2021-08-18 17:14:29 133

原创 分解质因数

分解质因数给定 n 个正整数 ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。做法和试除法判定质数是一致的,都是从i=2开始枚举,找到一个因数就开始不停的除,直到无法整除,结论除的次数,即为该因数的指数。接下来看代码:void decp(int x){ /*这里要知道一个性质,就是n的所有因子中最多只有一个是大于sqrt(n)的,因为如果有两个的话,相乘肯定大于n了 因为n就是可以写成质因数相乘的形式,所以我们还是可以只遍历到n/i,最后对n特判一下

2021-08-18 15:57:53 282

原创 试除法判定质数

试除法判定质数所谓质数,就是因数只有1和它本身的数,但是1既不是质数也不是合数。这时我们采用一种类似枚举的方式判断一个数是否为质数,具体方法就是从i = 2开始,找待判定数n的因数,我们用n%i,如果余数为0,那么说明找到了n的一个因数,这时n肯定不是质数,那么i应该找到多大停止呢,到n-1吗?显然有比这更好的选择,事实上我们可以把2到n之间的数分成两部分,一部分在2到根下n,另一部分在根下n到n,那么我们可以发现这样一个规律,就是对于n的因数来讲一个在前一部分,另一个一定在后一部分,所以,我们只要在前一

2021-08-18 15:10:17 637 1

原创 字符串哈希

字符串哈希是将一个字符串转换成一个数字,转换方法是将字符串视为一个p进制的数,比如ABCD,就可以看做 A * p^3 +B * p^2 + C*p^1 + D * p^0,但是,当字符串的长度很大的时候,就会出现转换成的数字无法表示的问题,这时就需要将转换的数字模上一个比较小的数,这个数一般取多少呢,取2 ^ 64,这样可以比较方便的判断两个字符串是否相等,当p取131或者13331时,如果两个字符串转换成的数字是相等的,则认为这两个字符串也是相等的。另外,我们可以

2021-08-08 16:52:32 267

原创 模拟散列表

哈希表的存储及定位方式有开放寻址法和拉链法,所谓开放寻址法。对于使用哈希表来讲最重要的是哈希函数的构造,一般来讲哈希的作用就是将范围比较大但是比较稀疏的数据映射到小范围的数据里面,而哈希函数就是实现此功能的函数,一般的做法是对每一个数据模上一个比较小的数n(n一般取10的5次方到10的6次方,注意,n要是一个质数),这样最终的范围就会在0到n之间。那么这时就会出现一个问题,就是万一有两个数同时对n取模结果相同怎么办,这是一个无法避免的问题,这时的解决方法就有两种,一种就是开放寻址法,当我将x映射到k之后,加

2021-08-08 16:16:53 93

原创 模拟队列解决滑动窗口

队列同样可以用数组模拟实现,因为队列有两个指针,头指针和尾指针,一般情况下头指针初始取0,尾指针初始取-1,这样判空比较方便,那么什么是滑动窗口呢,这个我也说不太清楚,看一下问题吧:这就是所谓的滑动窗口,首先我们分析一下,暴力的方法很容易想到,直接遍历,但是这样会超时,看如何优化呢,用模拟队列实现。想想一个已经大小固定为k的队列,对于数组元素,每次从队尾进入,对于当前队尾元素来说,如果待进入放入元素比当前队尾元素小,那么当前队尾元素就在以后的窗口中不可能被输出,因为它的下一个比他更小,这时就可以直接把当

2021-08-05 21:50:11 121

原创 用模拟栈实现单调栈

栈的基本操作就是栈顶插入元素,栈顶弹出元素,判断栈是否为空,以及查询栈顶元素,用数组模拟时,首先要确定栈顶指针top,假设top为-1,这样好操作一些,在栈顶插入就是++top,弹出就是直接–top,因为弹出是不用输出的,只有一个减一操作,所以top–也是可以的,至于判断是否为空,那么当top<0时就为空,否则,不为空,查询栈顶元素,直接输出s[top]就行了,下面看一下代码:#include<iostream>#include<algorithm>using name

2021-08-05 21:28:35 96

原创 最长连续不重复子序列

双指针求解双指针算法的特点就是在一个for循环的初始部分就定义i,j两个变量,在自增部分实现其中一个变量的变化,在循环体中实现另一个变量的自增。接下来看我们要解决的问题,给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。这个用双指针算法,要定义一个标志数组,我的想法是把标志数组定义成布尔型的,其实定义成整形是一样的。保持i不动,改变j,当前的数如果没出现过,就标记一下,接着往后走,如果遇到一个曾经出现过的数,j停止移动,这时i要往前移,移到哪里呢,移到和当前j的位置

2021-08-03 20:34:06 185

原创 螺旋矩阵的模拟解法

所谓螺旋矩阵就是形如这个题目的解法就是采用模拟的思想,模拟的是旋转的过程,这是按顺时针模拟的,首先i不变,j每次加一,当j达到边界之后,j保持不变,i加1,当i到达边界之后,i不变,j减1,当j到达边界之后,j不变,i减1。每一轮都按这个思想处理即可,问题在于边界怎么计算,就是简单的n吗,当然不是,比如对于j来讲,第一轮的时候向右可以达到n的边界,但是第二轮还可以吗,显然是不行的,所以这是我们需要在弄一个变量表示轮数,显然i,j的边界都和这个轮数有关,什么叫一轮的,当i,j回到开始时,这边是一轮,当然这

2021-07-31 14:55:08 132

原创 一维矩阵的差分

一维矩阵差分首先明确一点,差分是前缀和的逆运算,即要求一个数组a的差分数组b,就是要使得b数组的前缀和数组是a数组。那么如何构造差分数组呢?我们可以这样看,a[1]=b[1],a[2]=b[1]+b[2],a[3]=b[1]+b[2]+b[3],…a[n]=b[1]+b[2]+…+b[n],那么b[1]=a[1],b[2]=a[2]-b[1]=a[2]-a[1],b[3]=a[3]-b[1]-b[2]=a[3]-a[2],…,b[n]=a[n]-b[1]-b[2]-…-b[n - 1]=a[n]-a[n-

2021-07-20 09:22:07 360

原创 前缀和的计算

前缀和前缀和的题目一般形如如果使用暴力算法,对每一对的l, r都从a[l]开始加到a[r],那么可能会导致超时,其实我们可以另外再弄一个数组S,其中的元素S[i]就代表从a[0]到a[i]的元素和,这样我们要计算a中l到r只需要计算S[r] - S[l - 1]即可,这里要注意一点就是在存储a的时候,下标从1开始,这样比较方便,不需要特判,计算S的时候也从1开始计算即可。如果a从下标为0的地方开始存储,那么S[i]=S[i-1]+a[i]这个公式用起来就会非常不方便。具体代码如下:#include&

2021-07-19 09:36:09 272

原创 高精度加法

高精度加法所谓高精度加法,即两个大数相加,一般情况下,这两个大数都在千位以上,这时由于超出了数的表示范围,因此,我们一般将这种数作为字符串读入,然后相加的时候,是一位一位的从个位开始相加,注意要有进位,还要注意相加的顺序,将字符串转成数组的时候,是怎样存的,按大端还是小端,相加的时候找到个位所在的那一端进行相加。#include<iostream>#include<algorithm>#include<vector>using namespace std;

2021-07-16 11:30:56 70

原创 二分求n次方根

二分求n次方根以求x的三次方根为例,一般情况下x的三次方根一定在0到x之间,所以我们令l= 0, r = x,在l和r之间进行二分,但是当x小于1时,比如x = 0.001,很明显,x的三次方根不在0到x之间,这时我们二分的区间应该是(0,1)(这里都默认x > 0,当x为负数时方法是一样的),所以,我们应该二分的区间是(0,max(1,x)),但是上面的方法有一点麻烦,就是我要比较x和1,那么索性我直接取l和r与x无关,即在(-10000,10000)之间进行二分(具体区间根据题意判断),这样令

2021-07-16 09:52:44 368

原创 快速选择算法求第k个数

快速选择算法求第k个数快速选择算法的思想和快速排序十分接近,快速排序是在一组数中找一个数为基准,然后小于该数的放在数组右边,大于该数的放在数组左边,然后以该数为分界,左右递归求解,快速选择前面的思路和快排一样,只不过因为我们要求第k个数,不管是第k大还是第k小,假设求第k小的数,那么如果左半段的个数大于k,这第k小的数一定在左半段,只需对左半段递归即可,如果左半段的个数小于k,那么就在右半段,但是这时候要注意的一点就是整体的第k小,在右半段就是第k-sl小(假设sl是左半段的长度),那么这时只需对右半段递

2021-07-14 15:25:39 81

原创 编程细节整理

在效率方面,stdio产生的执行文件与iostream产生的执行文件相比尺寸小而且执行速度快

2021-06-06 16:20:31 68

原创 堆优化版Dijkstra算法

堆优化版Dijkstra算法朴素版Dijkstra算法的时间复杂度是o(n^2)的,当数据范围较大的时候,比如n= 10^5,那么肯定就会爆掉,所以我们要想办法对其进行优化。要想对一个算法进行优化,我们要分析一下它每一步的时间复杂度,对复杂度较高的步骤进行优化。具体的朴素dijkstra算法的思路可以参考朴素Dijkstra算法解决最短路问题对朴素dijkstra算法进行分析,我们可以发现浪费时间的地方主要发生在找当前距离源点最近的那个点,每次都需要对所有的点进行遍历,再加上外面的一层循环,总体的时间

2021-04-24 19:26:01 571

原创 朴素Dijkstra算法解决最短路问题

朴素Dijkstra算法解决最短路问题Dijkstra算法适合解决所有边权都是正数的单源最短路问题,朴素Dijkstra算法的时间复杂度是o(n^2)。下面分析一下它的具体思路:1、我们首先要清楚它解决的这类问题单源最短路是什么意思,所谓单源,就是说只有一个源点,求这个源点到其他点的最短路径。2、假设共有n个点,那么我们可以设一个数组dist[n],dist[i]用于存储源点到每个点的最短距离,假设源点为1,起始下标从1开始,那么显然,dist[1]=0,然后这个算法要在一次次的迭代中找到源点到某个点

2021-04-23 22:11:05 155

原创 BFS解决走迷宫问题

#BFS解决走迷宫问题下面是题目给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。输入格式第一行包含两个整数 n 和 m。接下来 n 行,每行包含 m 个整数(0 或 1

2021-03-28 09:19:54 266

原创 Tire字典树

Tire字典树Tire(字典树)是一种数据结构,一般用于统计和存储字符串,至于它的效率我并没有有怎么研究,但是有的大神说它的效率比哈希表高,是一种空间换时间的方式,我们这里采用二维数组来模拟实现Tire树,并进行字符串统计。比如有一个字符串集合,要存储几个字符串abcahfcbdasd那么利用字典树可以如下存储下面是一道来自acwing的题目维护一个字符串集合,支持两种操作:“I x”向集合中插入一个字符串x;“Q x”询问一个字符串在集合中出现了多少次。共有N个操作,输入的字符串

2021-03-17 22:12:54 270 1

原创 通过数组模拟实现单链表

通过数组模拟实现单链表一般情况下,在c或c++里面实现单链表需要使用结构体,这是一种动态链表,这种链表基本可以不受空间的限制,动态的分配内存,但是在c++中使用new运算符来申请空间速度很慢,在一般的算法题目中,可以采用数组来模拟链表,这是一种静态链表。这种模拟确实存在一定的空间浪费,但是我们只是为了解决算法题目,有一定的浪费不用太计较,另外还要注意一点,就是我们要使用两个数组,一个存插入顺序(即第几个插入的),一个存插入值,特别要注意它第一个插入的下标为零,但是在最后头指针head不一定指向0,因为这是

2021-03-13 10:55:34 361

原创 快速选择第k个数

快速选择第k个数给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列从小到大排序后的第k个数。输入格式第一行包含两个整数 n 和 k。第二行包含 n 个整数(所有整数均在1~109范围内),表示整数数列。输出格式输出一个整数,表示数列的第k小数。数据范围1≤n≤100000,1≤k≤n输入样例:5 32 4 1 5 3输出样例:3整体思想:利用快速排序的过程,快排过程中会把数组分成两部分,可以通过比较两边数组的长度与k的关系来确定k在哪一边,这样只需要对一边递

2021-03-12 22:10:11 279

原创 快速排序的实现

快速排序快速排序是一种常用的排序算法,其时间复杂度是O(nlogn),c++自带快排函数sort(),其实现和这里的快排类似但又不完全相同快速排序算法思想:先在待排序的数组a中任意找一个数据x,最好取中间的数a[(l+r)/2],其中l是最小下标,r是最大下标。找到这个数据后再采用双指针(其实是两个用来标记数组下标的变量),一个从头开始往后移动,一个从最后一个开始往前移动。当前面的指针i所指的数a[i]大于x时,停止移动,再向前移动后面的指针,知道后面指针j所指得到数啊a[j]小于x时停止(移动

2021-03-12 21:36:23 114

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除