算法刷题
算法学习
Wizard go
这个作者很懒,什么都没留下…
展开
-
作物杂交(DFS)
作物杂交作物杂交是作物栽培中重要的一步。已知有 N 种作物 (编号 1 至 N),第 i 种作物从播种到成熟的时间为 Ti。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。初始时,拥有其中 M 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。如存原创 2022-04-06 12:01:19 · 479 阅读 · 1 评论 -
打包(二分+贪心)
打包Lazy有N个礼物需要打成M个包裹,邮寄给M个人,这些礼物虽然很便宜,但是很重。Lazy希望每个人得到的礼物的编号都是连续的。为了避免支付高昂的超重费,他还希望让包裹的最大重量最小。二分思路:最大重量的最小值必然是在单个礼物的最大值和所有礼物的重量和之间,我们要在这个区间保证礼物能够分成M份,且这个重量最小。int l=max_w,r=sum;while(l<r){ int mid=l+r >>1; //如果mid重量能够分成小于m份,说明有更小的mid,区间往左压缩原创 2022-04-04 15:34:55 · 489 阅读 · 0 评论 -
839.模拟堆
维护一个集合,初始时集合为空,支持如下几种操作:I x,插入一个数 x;PM,输出当前集合中的最小值;DM,删除当前集合中的最小值(数据保证此时的最小值唯一);D k,删除第 k 个插入的数;C k x,修改第 k 个插入的数,将其变为 x;现在要进行 N 次操作,对于所有第 2 个操作,输出当前集合的最小值。输入格式第一行包含整数 N。接下来 N 行,每行包含一个操作指令,操作指令为 I x,PM,DM,D k 或 C k x 中的一种。输出格式对于每个输出指令 PM,输出一个结果,原创 2022-01-27 16:27:12 · 101 阅读 · 0 评论 -
240.食物链
动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。A 吃 B,B 吃 C,C 吃 A。现有 N 个动物,以 1∼N 编号。每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这 N 个动物所构成的食物链关系进行描述:第一种说法是 1 X Y,表示 X 和 Y 是同类。第二种说法是 2 X Y,表示 X 吃 Y。此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句原创 2022-01-27 16:12:10 · 98 阅读 · 0 评论 -
836. 合并集合
一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。现在要进行 m 个操作,操作共有两种:M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;输入格式第一行输入整数 n 和 m。接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。输出格式对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否原创 2022-01-26 13:35:17 · 62 阅读 · 0 评论 -
17.Tire树
维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。输入格式第一行包含整数 N,表示操作数。接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中原创 2022-01-26 11:57:01 · 78 阅读 · 0 评论 -
831.KMP字符串
给定一个模式串 S,以及一个模板串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。模板串 P 在模式串 S 中多次作为子串出现。求出模板串 P 在模式串 S 中所有出现的位置的起始下标。输入格式第一行输入整数 N,表示字符串 P 的长度。第二行输入字符串 P。第三行输入整数 M,表示字符串 S 的长度。第四行输入字符串 S。输出格式共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。数据范围1≤N≤1051≤M≤106输入样例:3aba5a原创 2022-01-25 17:10:18 · 811 阅读 · 0 评论 -
154.滑动窗口
给定一个大小为 n≤106 的数组。有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。你只能在窗口中看到 k 个数字。每次滑动窗口向右移动一个位置。以下是一个例子:该数组为 [1 3 -1 -3 5 3 6 7],k 为 3。窗口位置 最小值 最大值[1 3 -1] -3 5 3 6 7 -1 31 [3 -1 -3] 5 3 6 7 -3 31 3 [-1 -3 5] 3 6 7 -3 51 3 -1 [-3 5 3] 6 7 -3 51 3 -1 -3 [5 3 6] 7原创 2022-01-25 11:49:31 · 77 阅读 · 0 评论 -
830.单调栈
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。输入格式第一行包含整数 N,表示数列长度。第二行包含 N 个整数,表示整数数列。输出格式共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。数据范围1≤N≤1051≤数列中元素≤109输入样例:53 4 2 7 5输出样例:-1 3 -1 2 2如何构建一个单调栈每当有一个数i,如果栈顶元素比i大,那么该元素后面都不可能会用到,因为已经有原创 2022-01-25 11:30:23 · 334 阅读 · 0 评论 -
788.逆序对的数量
逆序对的数量【题目描述】**给定一个序列有n个数,求n个数中逆序对的个数,逆序对的定义:i < j && a[i] > a[j]。【输入格式】第一行包含整数 n第二行包含 n【输出格式】输出一个整数,表示逆序对的个数。【数据范围】1≤n≤100000【输入样例】62 3 4 5 6 1【输出样例】5解法本质还是归并排序,对于左右两段有序序列如果 a[i] > a[j] ,那么i到mid之间的数都大于 a[j] ,则其中的逆序对数量为 mi原创 2022-01-21 14:39:06 · 288 阅读 · 0 评论 -
1922. 懒惰的牛
1922. 懒惰的牛这是一个炎热的夏日。懒洋洋的奶牛贝茜想将自己放置在田野中的某个位置,以便可以在短距离内尽可能多地吃到美味的草。贝茜所在的田野中共有 N 片草地,我们可以将田野视作一个一维数轴。第 i 片草地中包含 gi 单位的青草,位置坐标为 xi。不同草地的位置不同。贝茜想选取田野中的某个点作为她的初始位置(可能是某片草地所在的点)。只有一片草地与她的初始位置的距离不超过 K 时,贝茜才能吃到那片草地上的草。如果贝茜选择最佳初始位置,请确定她可以吃到的青草最大数量。输入格式第一行包原创 2022-01-21 10:40:30 · 291 阅读 · 0 评论 -
800.数组元素的目标和
给定两个升序排序的有序数组A和B,以及一个目标值x。数组下标从0开始。请你求出满足A[i] + B[j] = x的数对(i, j)。数据保证有唯一解。输入格式第一行包含三个整数n,m,x,分别表示A的长度,B的长度以及目标值x。第二行包含n个整数,表示数组A。第三行包含m个整数,表示数组B。输出格式共一行,包含两个整数 i 和 j。数据范围数组长度不超过100000。同一数组内元素各不相同。1≤数组元素≤109输入样例:4 5 61 2 4 73 4 6 8 9输出样例:原创 2022-01-19 17:20:40 · 329 阅读 · 0 评论 -
802.区间和
区间和假定有一个无限长的数轴,数轴上每个坐标上的数都是0。现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。近下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。输入格式第一行包含两个整数n和m。接下来 n 行,每行包含两个整数x和c。再接下里 m 行,每行包含两个整数l和r。输出格式共m行,每行输出一个询问中所求的区间内数字和。数据范围−109≤ x ≤109,1≤ n,m ≤105,−109≤ l ≤ r ≤109,原创 2022-01-19 14:02:07 · 84 阅读 · 0 评论 -
最长不重复子序列
双指针指针i,j一开始都在初始位置,i固定,j右移,对j经过的字符我们标识该字符出现的次数,当出现重复字符时,j固定,i移动到该字符出现的第一次的下一个位置,同时将移动过程经过的字符次数减1const int N=100010;int S[N]={0};int res = 0;for (int j = 0, i = 0; j < s.size(); j ++ ){ S[s[j]] ++ ;//标识该字符出现次数 while (i < j && S[s.原创 2022-01-18 18:04:13 · 365 阅读 · 0 评论 -
1945. 奶牛棒球
农夫约翰的 N 头奶牛排成一排,每头奶牛都位于数轴中的不同位置上。它们正在练习投掷棒球。农夫约翰观看时,观察到一组三头牛 (X,Y,Z) 完成了两次成功的投掷。牛 X 把球扔给她右边的牛 Y,然后牛 Y 把球扔给她右边的牛 Z。约翰指出,第二次投掷的距离不少于第一次投掷的距离,也不超过第一次投掷的距离的两倍。请计算共有多少组牛 (X,Y,Z) 可能是约翰所看到的。输入格式第一行包含整数 N。接下来 N 行,每行描述一头牛的位置。输出格式输出奶牛三元组 (X,Y,Z) 的数量。(X,Y,原创 2022-01-17 12:02:17 · 283 阅读 · 0 评论 -
786.第k个数
#include<iostream>using namespace std;const int N=100010;int quick_sort(int q[],int l,int r,int k){ if(l>=r) return q[l]; int x=q[l+r>>1]; int i=l-1,j=r+1; while(i<j) { do i++;while(q[i]<x); do.原创 2022-01-16 10:40:34 · 48 阅读 · 0 评论 -
3596. a+b
实现一个加法器,使其能够输出 a+b 的值。输入格式输入包含多组测试数据。每组数据占一行,包含两个正整数 a,b。输出格式每组数据输出一行答案,表示 a+b 的值。数据范围每个输入最多包含 100 组数据。a,b 最多不超过 1000 位。输入样例:2 610000000000000000000 10000000000000000000000000000000输出样例:810000000000010000000000000000000#include<iostream&g原创 2022-01-16 10:09:47 · 52 阅读 · 0 评论 -
分形之城.
从上图可以得出城市等级N和房屋数量的关系:房屋数量=22N要求两个城市之间的距离,我们就需要计算两个城市的坐标。每一座N级城市由4座N-1级城市组成,所以我们想要计算calc(N,M),M编号的房屋在N级城市的编号,可以转化成求对应编号在N-1级城市的坐标。M mod 22N-2:M编号的城市在N-1级的城市未经过翻转变化前,对应位置的编号。M / 22N-2:M编号的房屋在4座N-1级的城市中的哪一块区域。对应区域如下:求得N-1级的房屋位置(x,y)后,我们需要对根据4个区域进行坐标变化来.原创 2021-11-03 10:02:58 · 84 阅读 · 0 评论 -
约数之和(分治)
思路:1.对整数A进行质因数分解,统计质因数的个数即pn。2.对于本题,如果直接对上面进行等比数列的计算会WA,将其拆分成两种情况:奇数和偶数考虑。则sum(p,c)可以表示为对偶数:sum(p,c-1)*p+1对奇数:sum(p,(c-1)/2) * (p(c+1)/2+1)代码:#include<iostream>using namespace std;const int mod=9901;//快速幂int qmi(int a,int b){ int res=1%..原创 2021-10-29 14:00:50 · 83 阅读 · 0 评论 -
奇怪的汉诺塔
![qi三塔问题对于三塔模型(A,B,C)的汉诺塔,我们有一下思路:1.将n-1个圆盘从A移动到B2.把第n个圆盘从A移动到C3.把n-1个圆盘从B移动到C我们用d[n]来表示移动n个圆盘所需要的最少次数,由以上3点可得:d[n]=d[n-1] * 2+1这样我们可以得到三塔问题下各圆盘移动的最少次数。四塔问题对于四塔问题,假设有n个圆盘,我们可以执行如下操作:1.将k个圆盘从A移动到B,该问题是在四塔模式下执行。2.将 n-k 个圆盘从A移动到D,由于B已被占用,该问题是在三塔模原创 2021-10-25 14:05:38 · 183 阅读 · 0 评论 -
费解的开关
思路一:枚举所有情况,225种方案,时间复杂度高,超时。所以我们需要挖掘一下其中有没有什么规律,由于对每一个开关操作,它的上下左右都会发生改变。与之前飞行员兄弟该题同理。1.对同一个开关重复操作没有意义,即在每一个方案中,一个开关有且仅可能执行一次。2.各个开关的执行顺序不影响最后的结果。3.当有一行全1后,我们要对它相邻一行i执行状态更换,只能通过(i+1)操作,而不影响全1那行。这里我们从第一行开始看,当我们确定了第一行的操作后,后续每一行的操作方案都是固定的,即当第一行只剩下最后一个0时,要.原创 2021-10-25 00:54:27 · 250 阅读 · 0 评论 -
递归实现排列型枚举
这里相当于在递归实现组合型枚举的基础上,在n个数中选取n个数,且是无序的,也就是说每一个数都会出现在递归搜索树的每一层,所以对于每条路线我们都需要搜索n次,由于每一次选取的数不同,我们需要判断是否已经将该数添加到了路径。递归搜索树如下:代码:#include<iostream>#include<algorithm>using namespace std;int n;int path[10];int flag[10];//用于标识该数是否已经选取void dfs(i.原创 2021-10-23 16:24:23 · 354 阅读 · 0 评论 -
递归实现组合型枚举
解法一:一共有Cmn 种方案,因为要求从小到大输出,我们可以从1开始选,之后每次递增选取,假设要在1-4中选3个树,画递归搜索树:从左到右,从上到下对该树遍历,最后一层的叶子节点即为方案数。代码:#include<iostream>#include<algorithm>using namespace std;int n,m;int path[i];void dfs(int u,int start)//u表示层数,start表示当前要从第几个数开始搜{ if(.原创 2021-10-23 16:02:16 · 194 阅读 · 0 评论 -
递归实现指数型枚举
因为要求同一行的数升序排列,这里我们从第一个数开始选,对于每一个数有两种情况,选和不选,对于n个数,一共有2n种可能。我们可以通过递归搜索树对所有方案遍历。如图,左子树代表选,右子树代表不选,对于n个数,生成的递归搜索树一共有n层,从0开始算,最后的叶子节点即为所有方案。解法1:用位运算记录方案#include<iostream>using namespace std;int n;void dfs(int x,int state)//x表示当前层数,state表示当前已经选择的.原创 2021-10-22 21:33:18 · 84 阅读 · 0 评论 -
飞行员兄弟(超详细易懂)
对于输入样例,是一个4*4的矩阵,在这里我们用"1"表示“+”,“0”表示“-”。对于终态是一个全为0的矩阵。由于每对一个开关操作,对应的行和列都会发生改变,由题可得,我们做的就是通过若干次开关操作构建一条从初态到终态的路线。以示例为例,输出了(1,1)->(1,3)->(1,4)->(4,1)->(4,3)->(4,4),依次对上述位置的开关进行了操作。我们用二进制来表示上述方案即为:0 1 1 10 0 0 00 0 0 00 1 1 .原创 2021-10-20 09:47:18 · 317 阅读 · 0 评论 -
起床困难综合症
解法1:位运算只关注当前进行运算的一位,对其他位无影响。对于输入的初始攻击x,需要进行n次op运算,得到最大攻击力。把最后的输出以二进制表示,即我们希望输出的最大攻击力有尽可能多的1。对于初始攻击x,假设一共有k位,每一位只有0或1两种取值。我们把每一位单独拿出来做n次运算。来确定该位应该填0还是1。依次从高位到低位确定。比如:对于一个4位的数_ _ _ _,我们需要进行3次op运算,假设最高位第3位分别是0或1的两种情况,op[i]运算对应参数为t[i],则对t[i]>>3&1.原创 2021-10-18 16:06:44 · 98 阅读 · 0 评论 -
最短Hamilton路径
#include<iostream>#include<cstring>using namespace std;int f[1<<20][20];int weight[20][20];int main(){ memset(f,0x3f,sizeof(f)); f[1][0]=0; int n; cin>>n; for(int i=0;i<(1<<n);i++) for(int.原创 2021-10-15 15:52:42 · 119 阅读 · 0 评论 -
a^b mod q
看到这个题第一反应就是直接循环挨个相乘求解,即相乘b次,这样时间复杂度为O(n),提交超时。所以这里我们采用快速幂求解,将b看成二进制数处理:b&1:得到b的二进制数的最低位b>>1:右移舍弃b的二进制最低位假设b的二进制有k位,k=log2(b+1),时间复杂度变为log2b.由此我们得到如下代码:#include<iostream>using namespace std;int main(){ int a,b,p; cin>>.原创 2021-10-12 21:55:17 · 90 阅读 · 0 评论 -
198. House Robber
解法1:由于小偷每个房屋不能连续,所以对于偷窃到当前房屋i的最高金额等于当前房屋的金额和前面所得到的最高金额之和。可以得到一下动态转移方程,dp数组表示到该房屋时已经窃取到的最高金额。dp[i]=max(dp[:i-1])+nums[i]在代码中我们直接使用nums数组操作,数组中每一个元素表示小偷到该房屋时的最大金额。nums[i]=max(nums[:i-1])+nums[i]最后返回该数组最大值,最大值的位置为i-1或者i-2class Solution: def rob(self.原创 2021-08-26 00:21:04 · 40 阅读 · 0 评论 -
746. Min Cost Climbing Stairs
这里有一个关键点要注意,最终是要爬到楼层顶部。设置一个dp数组来存放到达该阶梯所需要的最小花费,如dp[2]表示到达阶梯2的最小花费。可以如上图所示,要想爬到顶部,可以从阶梯0或者阶梯1出发,要到达top,有两种方法:要么从cost[1]开始爬两步,所需消耗体力为dp[1]+cost[1],要么从cost[2]开始爬一步,所需消耗体力为dp[2]+cost[2],dp[2]又有两种思路,从0走两步,dp[0]+cost[0],或者从1走一步dp[1]+cost[1]。观察上式可知如下公式:d.原创 2021-08-23 17:49:45 · 80 阅读 · 0 评论 -
25. Reverse Nodes in k-Group
解法:这里用栈解决,每次栈中存入k个元素,利用栈后进先出的特性将元素链接到新链表中,若栈元素不足k个,则直接链接剩余元素# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def reverseKGroup(self.原创 2021-08-03 17:22:19 · 57 阅读 · 0 评论 -
206. Reverse Linked List
解法1:头结点插入class Solution: def reverseList(self, head: ListNode) -> ListNode: res=ListNode(-1) p=head while p: cur=p.next p.next=res.next res.next=p p=cur return res.nex.原创 2021-08-03 17:17:40 · 59 阅读 · 0 评论 -
83. Remove Duplicates from Sorted List
这题是比删除所有重复元素更简单一点,一次遍历,让指针ntr指向第一个元素,后续后重复一次删除即可class Solution: def deleteDuplicates(self, head: ListNode) -> ListNode: res=ListNode(-1) res.next=head ntr=head if not ntr: return head while ntr.n.原创 2021-08-03 15:41:29 · 37 阅读 · 0 评论 -
82. Remove Duplicates from Sorted List II
解法1:这道题主要是删除所有重复元素,最简单的方法就是设置一个指针ntr指向第一个元素,ntr.next和ntr.next.next指向重复元素,如果有重复元素,删除第一个重复元素,ntr.next=ntr.next.next,指针后移,判断接下来是否还有重复元素# self.next = nextclass Solution: def deleteDuplicates(self, head: ListNode) -> ListNode: res=List.原创 2021-08-03 11:32:17 · 63 阅读 · 0 评论 -
61. Rotate List
主体思想都是构建环形链表解法1:# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def rotateRight(self, head: ListNode, k: int) -> ListNode: ..原创 2021-08-01 17:04:31 · 46 阅读 · 0 评论 -
24. Swap Nodes in Pairs
解法1:递归# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def swapPairs(self, head: ListNode) -> ListNode: if not head or .原创 2021-07-30 17:12:25 · 58 阅读 · 0 评论 -
23.Merge Sorted List
解法1:递归进行归并排序# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def mergeKLists(self, lists: List[ListNode]) -> ListNode: de.原创 2021-07-28 16:53:08 · 81 阅读 · 0 评论 -
21. Merge Two Sorted Lists
解法1:迭代:依次比较两个链表的元素,元素大的指针位置不变,元素小的将元素存入链表,指针后移,直到有一个链表遍历完# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def mergeTwoLists(self, l1.原创 2021-07-18 23:52:05 · 54 阅读 · 1 评论 -
19. Remove Nth Node From End of List
关键:要删除一个节点,我们需要找到它的前驱节点解法1:先计算链表长度,再根据倒数位置计算元素位置,再移动指针到前一个节点# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def removeNthFromEnd(s.原创 2021-07-18 23:34:24 · 84 阅读 · 0 评论 -
2.Add two Numbers
Add Two Numbers解法1# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListN原创 2021-07-16 00:20:56 · 44 阅读 · 0 评论