![](https://img-blog.csdnimg.cn/20201014180756724.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
算法
抓抓璐璐小可爱(๑• . •๑)
这个作者很懒,什么都没留下…
展开
-
每日学习记录帖
每日一题记录贴~原创 2022-05-10 23:05:33 · 282 阅读 · 2 评论 -
剑指offer 专项突破版 119、最长连续序列
题目链接思路同样的可以转化为并查集来做,可以把相邻的数字放到一个子集中,每当搜索到一个数字时就判断和他相邻的数字是否在集合中,如果在就合并,为了方便记录每个集合的大小,可以用一个count集合记录每个子集的大小,在合并集合的时候也要更新count数组。这个题需要注意的就是并查集的另一种使用方式:首先把所有数字放入allNum中,同时初始化fathers集合和count集合然后遍历每一个allNum中的数字,对于每个数字都判断一下相邻的数字是否在集合中,如果在的话就进行合并处理最后找出最大集合元原创 2022-05-10 22:48:54 · 314 阅读 · 0 评论 -
剑指offer 专项突破版 118、多余的边
题目链接思路这个题是要找处于环的边,可以转化为用并查集处理的问题首先把所有结点初始化,每个人的根节点都是自己每遍历一个边就合并两个子集如果遍历到某一个边,发现合并前二者就是一个子集(也就是union函数返回false),那么这个边就是最后一个环的边,也就是我们要找的多余的边class Solution { public int[] findRedundantConnection(int[][] edges) { int n = edges.length; int[原创 2022-05-10 22:48:16 · 917 阅读 · 0 评论 -
剑指offer 专项突破版 117、相似的字符串
题目链接思路这道题和上题有点类似,代码主题框架相同,并不需要像拓扑排序那样,先建图注意看主题框架类似邻接矩阵!还有就是注意如何判断两个字符串是不是相似的,因为题目中说了所有的字符串都是变位词,所以我们可以遍历一遍两个字符串,遇到不一样的字符就+1,最后如果不相同的字符串<=2 那么就说明是相似的class Solution { public int numSimilarGroups(String[] strs) { int[] fathers = new int[原创 2022-05-08 21:22:41 · 943 阅读 · 0 评论 -
剑指offer 专项突破版 116、省份数量
题目链接思路对于这种图的分类问题是经典的并查集的运用并查集的关键在于两个函数 findFather用来寻找根节点并更新,union用来判断是否需要把两个结点合二为一注意union函数中后面的更新的是fathers[fatherOfI]class Solution { public int findCircleNum(int[][] isConnected) { int[] fathers = new int[isConnected.length]; fo原创 2022-05-08 21:22:11 · 176 阅读 · 0 评论 -
剑指offer 专项突破版 115、重建序列
题目链接思路这个题注意,图的结点应该是后面的序列中出现的所有的字符!还有一点在于,对于某个序列[1,2,3],我们只需要创建1指向2的弧,2指向3的弧即可,并不需要创建1指向3的弧,尽管1的优先级比3高,但是只要建立了1->2的弧,那么就可以保证1不出去,3也绝对出不去!至于如何判断是否只有一种拓扑排序的结果,只要每次都判断一下,此时队列里是不是只有一个元素!最后注意一下判断数组相等的APIArrays.equals(orgs,build.stream().mapToInt(e->原创 2022-05-08 21:11:35 · 306 阅读 · 0 评论 -
剑指offer 专项突破版 114、外星文字典
题目链接思路这种题目难点就两个 抽象为图并构建邻接表、拓扑排序首先我们可以确定的是所有出现的字符是图中的结点,如果某个字符ch1优先级大于ch2,那么就应该存在一条ch1指向ch2的弧我们可以根据words数组中的顺序找到单词的优先级关系,因为单词是字典序,所以只需要找到前后两个字母第一个不一样的字符 那么必然有前面的字符优先级高于后面的字符。但是有两种特殊情况,如果前面是后面的子串,那么自然找不到不一样的字符,如果后面是前面的子串,那么排序是错误的。需要注意的是 某个单词如gril,字符之间并原创 2022-05-08 21:10:52 · 444 阅读 · 0 评论 -
剑指offer 专项突破版 113、课程顺序
题目链接思路大一就做过的经典拓扑排序的题目~关于拓扑排序有两点应该注意的。首先是图的建立。一般是用邻接表表示,对应着Map。与此同时在建立图的过程中找到每个结点的入度值,可以用数组也可以用Map。还有就是在建立图之前要先在Map中创建对应的结点然后是拓扑排序的过程,拓扑排序我们是使用BFS来完成的,首先建一个队,然后把所有入度为0的结点放入。后续就不断取出队列的元素,然后利用邻接表更新入度表,遇到入度为0的结点就再次入队,直至队空class Solution { public int[原创 2022-05-08 21:10:20 · 415 阅读 · 0 评论 -
剑指offer 专项突破版 112、最长递增路径
题目链接思路之前在做dp的题目时有一种做法是从大到小递归地计算,同时用一个数组保存状态,此题正是运用了这个思路,因为某个结点的最大递增路径就是1+和他相邻的比他大的结点的最大路径注意递归函数maxAscLength返回坐标为i,j结点的最大递增路径的值并进行填充class Solution { public int longestIncreasingPath(int[][] matrix) { int max = 1; int[][] maxPath = new in原创 2022-05-08 21:09:48 · 219 阅读 · 0 评论 -
剑指offer 专项突破版 111、计算除法
题目链接思路这个题可以看作一个寻找路径的问题~我们把所有出现的数字看作一个结点 那么这道题算除法就是让我们找到两个结点间的路径积是多少 而且有向图的边是有权重的,因此可以看作一个有向网~注意两个结点 如果E(a,b) = m 则E(b,a) = 1/m还有一点在于 E(a,b)表示a/b,如果我们要找a/c 我们可以找到a/b,然后再找到b/c,这两个结果应该做乘法,所以求的是路径积最后是如何表示图?我们可以用一个Map来表示结点和边的映射,具体的value还是一个Map,是临近节点和权重的映原创 2022-05-03 23:43:17 · 166 阅读 · 0 评论 -
剑指offer 专项突破版 110、所有路径
题目链接思路一般这种所有路径问题,适合用DFS因为这个是有向图且不存在环 所以不需要visited集合!PS: 我倒认为这个更像回溯~class Solution { List<List<Integer>> result; public List<List<Integer>> allPathsSourceTarget(int[][] graph) { result = new ArrayList<>();原创 2022-05-03 23:42:41 · 274 阅读 · 0 评论 -
剑指offer 专项突破版 109、开密码锁
题目链接思路这个题目和上一个题目有点类似,只不过上一个题的路径中的结点是已经的,所以我们可以有一个notVisited集合,但是这个题目的路径未知,为了不重复遍历,必须要设置一个visited集合最重要的一点在于,通过函数生成相邻结点时,不需要考虑是否visited过,因为在双向奔赴的过程中,如果某一个结点v在set2中,那么他肯定存在于visited集合中,如果因为这个而不把他加到相邻结点中,那么就永远也找不到set1中的元素出现在set2中的情况!所以总而言之,还是要返回所有的临近结点~c原创 2022-05-03 23:42:10 · 135 阅读 · 0 评论 -
剑指offer 专项突破版 108、单词演变
题目链接思路这种可以抽象成最短路径问题 每个单词是一个结点,如果两个单词只有一个字母的差距,那么他们之间有一条边,最终的目的是寻找开始单词和结束单词的最短路径因此这个题可以用BFS来解决 通过用队列辅助BFS 每一轮遍历结束后都给count++ 这样直到某一次队列中出现了target,就算是最终找到了因此我们可以用一个函数来获取某个单词可以转换为的所有的单词,也就是说在获取所有和该结点相邻的结点,注意这个函数要返回所有相邻的结点,不管是否遍历过class Solution { publ原创 2022-05-03 23:41:31 · 170 阅读 · 0 评论 -
剑指offer 专项突破版 107、矩阵中的距离
题目链接思路一般而言找最短距离 要先考虑BFS这道题应该是0找1首先我们把所有的0顶点放入队列 然后依次出队 把所有相邻的1顶点放入另一个队列那么此时第二个队列的所有的顶点距离都是1 然后再把和第二个队列相邻的所有的1顶点放入第三个队列。。。注意要放入队列还有一个条件 就是我们如果成功通过0顶点更新了1顶点的距离的话 那就把改1顶点放入队列if(result[pos[0]][pos[1]] + 1 < result[x][y]){ result[x][y] = result[原创 2022-05-03 23:40:44 · 128 阅读 · 0 评论 -
剑指offer 专项突破版 106、二分图
题目链接思路这个题仍然是注意思路,把二分图转化为给顶点涂色如果每一条边所依附的两个顶点都是不同的颜色 那么他就是一个二分图所以我们的搜索模板 最外层是遍历所有的顶点 如果该顶点尚未上色 就调用辅助函数对于辅助函数 我们先给该顶点上色 然后依次处理和该顶点相邻的所有顶点如果相邻的顶点涂色了 判断是否和当前顶点颜色相反如果没有涂色 那就对该顶点递归调用辅助函数递归class Solution { public boolean isBipartite(int[][] graph原创 2022-05-03 23:40:12 · 298 阅读 · 0 评论 -
剑指offer 专项突破版 105、岛屿的最大面积
题目链接思路这个题就是搜索 不管是dfs或者是bfs都可 反正搜索最多相邻的1的个数就好 主要就是熟悉一下模板首先最外层一个循环 遍历所有结点,如果该节点没有被遍历过,那就调用辅助函数还需要学习的是这种迷宫走法 如何快速用代码实现BFS 用队列~class Solution { int max; int[][] grid; boolean[][] isVisited; public int maxAreaOfIsland(int[][] grid) {原创 2022-05-03 23:39:40 · 181 阅读 · 0 评论 -
剑指offer 专项突破版 104、排列的数目
题目链接思路完全背包问题(可以重复选择) 思路和上一道题类似~设f(i)为用数组所有元素凑成i的可能的数目,那么有f(i) = Σ f(i-nums[j]),比如数组元素为[1,2,3] 需要凑8,那么某一步需要求f(5),也就是说凑成5的可能的数目。那么这个可能的总数有三种 先凑4再加上1,先凑3再加上2,先凑2再加上3。所以凑成和为5的可能数目就是上述三个数目的和边界情况 f(0) = 1 于此同时还有凑不成的情况 所以我们最初可以把数组所有元素初始化为0class Solution {原创 2022-04-28 22:21:14 · 180 阅读 · 0 评论 -
剑指offer 专项突破版 103、最少的硬币数目
题目链接思路这种题目可以无限选择,属于课重复选择的背包问题可以令f(i)为凑成面值i所需要的最少硬币数,那么f(i)可以是f(i-coins[0])+1,也就是说在凑成面值为i-coins[0]的基础上再加1枚硬币,也可以是是f(i-coins[1])+1,也就是说在凑成面值为i-coins[1]的基础上再加1枚硬币所以说 f(i) = min{f(i-coin)+1}边界条件 f(0) = 0,当目标数值是0时0枚硬币就可以还有一点在于初始化的值,把数组每个元素都初始化为amount+1 这原创 2022-04-28 22:20:39 · 207 阅读 · 0 评论 -
剑指offer 专项突破版 102、加减的目标值
题目链接思路这个题目首先在于转化,把题目转化为从数组中选出一些数,使他们的和为 sum+target >> 1设f(i,j)为前i个元素可以选出和为j的子元素的选法如果不选择第i个 f(i,j) = f(i-1,j)如果选择第i个 f(i,j) = f(i-1,j-nums[j])class Solution { public int findTargetSumWays(int[] nums, int target) { int su原创 2022-04-28 10:30:58 · 126 阅读 · 0 评论 -
剑指offer 专项突破版 101、分割等和子集
题目链接思路这个题本质就是问能否选择部分元素元素使其和为数组元素总和的一半,所以设f(i,j)为能否从前i个元素中挑选出和为j的部分元素,那么状态转移方程为如果选择了nums[i] f(i,j) = f(i-1,j-nums[i]) 也就是说,如果选择当前值nums[i] 那么能否选出和为j的元素,取决于前i-1个元素能否选出和为j-nums[i]的元素如果不选择nums[i] f(i,j) = f(i-1,j) 这代表不选择当前值nums[i]的话 能否选出和为j的元素,取决于前i-1个元素能原创 2022-04-28 10:30:26 · 127 阅读 · 0 评论 -
剑指offer 专项突破版 100、三角形中最小路径之和
题目链接思路这个题就是要区分一下边界数字和非边界数字边界数字的最大值只能是上一个边界+cost[i]但是非边界的数字可以是上一行相邻数字的最小值+cost[i]class Solution { public int minimumTotal(List<List<Integer>> triangle) { List<Integer> dp = triangle.get(0); for(int i = 1 ; i < tria原创 2022-04-28 10:29:54 · 90 阅读 · 0 评论 -
剑指offer 专项突破版 99、最小路径之和
题目链接思路这道题和上到题类似,设f(i,j)为从原点走到坐标为(i,j)的地点的最小路径因此有f(i,j)=min{f(i-1,j),f(i,j-1)}+cost(i,j)对于边界值,就是从开头到现在的累加和同样可以用一个数组保存~class Solution { public int minPathSum(int[][] grid) { int[] dp = new int[grid[0].length]; dp[0] = grid[0][0];原创 2022-04-27 00:01:52 · 80 阅读 · 0 评论 -
剑指offer 专项突破版 98、路径的数目
题目链接思路这种路径类题一般是用f(i,j)代表走到了坐标为(i,j)的位置这个题可以设f(i,j)代表从原点走到坐标为(i,j)位置的路径的条数因此f(i,j) = f(i-1,j) + f(i,j-1)对于边界值 f(0,j) f(i,0)都只能一条路走到黑 所以都是1这道题注意的点在于 我们可以状态压缩到用一维数组解决~ 此前都是用两行 但是其实可以更节约 用一行即可我们假设这一行在更新前存储的是f(i-1,j)的值,且我们要从左到右填充~在计算f(i,j)时,需要用到的是f(i-1原创 2022-04-27 00:01:18 · 1082 阅读 · 0 评论 -
剑指offer 专项突破版 96、字符串交织
题目链接题目链接这道题令f(i,j)是一个布尔值,代表s1前i个字符、s2前j个字符能不能交织成s3的前i+j+1个字符(都是从0开始索引的)首先找递推关系,令ch1 = s1.charAt(i) , ch2 = s2.charAt(j) , ch3 = s3.charAt(i+j+1);如果ch1=ch2 f(i,j)=f(i-1,j) 也就是说本次能否交织成功取决于s1前i-1个字符、s2前j个字符能不能交织成s3的前i+j个字符如果ch3=ch2 f(i,j)=f(i,j-1) 解释同上原创 2022-04-27 00:00:45 · 777 阅读 · 0 评论 -
剑指offer 专项突破版 97、子序列的数目
题目链接思路设f(i,j)是t的前j个字符在s前i个字符中出现的次数如果s[i]=t[i] 那么在选择子串的时候,可以用s[i]去匹配t[i] (此时f(i,j)=f(i-1,j-1)),也可以不用s[i]去匹配t[i] (此时f(i,j)=f(i-1,j))如果s[i]!=t[i] 那么s[i]并不能去匹配t[i] 此时f(i,j)=f(i-1,j)所以状态转移方程为f(i,j) = f(i-1,j-1) + f(i-1,j) 相等f(i,j) =f(i-1,j) 不等注意边界原创 2022-04-27 00:00:08 · 172 阅读 · 0 评论 -
剑指offer 专项突破版 95、最长公共子序列
题目链接思路这道题前面都是做的单序列的题目,也就是说输入的内容是一个数组或者是字符串。现在以及后面的几道题都是双序列,也就是说要处理的数据有两个数组或者字符串,对于双序列的题目,一般的状态转移方程有两个参数,因此我们需要找到f(i,j)和f(i-1,j-1)、f(i-1,j)、f(i,j-1)的关系假设f(i,j)是s1的前i个字符和s2的前j个字符可以形成的最大公共序列,那么最终的结果即为求f(s1.length(),s2.length())首先找递推关系(这里书上讲的很清楚)如果chi =原创 2022-04-26 23:59:17 · 133 阅读 · 0 评论 -
剑指offer 专项突破版 94、最少回文分割
题目链接思路我们设f(i)代表把前i个子串全部分为回文的最小分隔次数,那么便有f(i) = min{f(j)+1} 其中0<= j <=i 且f(j)为回文当然还有个特例就是如果[0,i-1]自己就是一个回文子串 那么f(i)=0因为每次都要判断任意两个子串是不是回文,因此我们可以提前处理以下,用二位数组isPal记录某子串S[i,j]是不是回文class Solution { public int minCut(String s) { // 提前原创 2022-04-26 23:58:45 · 237 阅读 · 0 评论 -
剑指offer 专项突破版 93、最长斐波那契数列
题目链接思路假设f(i,j)代表以A[j]为最后一个数字,A[i]为倒数第二个数字的斐波那契数列的长度,那么如果有A[k]使得A[k] + A[j] = A[i],就可以得到f(i,j)=f(j,k)+1所以可以用二重循环来实现 但是有几点需要注意对于任意两个索引ij(i>j),都有f(i,j)=2,因为他们两个的子串长度是2对于某个确定的A[i] A[j] 当我们想快速找到数组中是否存在A[k]时可以先把数组所有元素放入哈希表(val:index),这样就可以在O(1)的时间内找到某元原创 2022-04-21 23:59:33 · 118 阅读 · 0 评论 -
剑指offer 专项突破版 92、翻转字符
题目链接思路假设f(i)为前i个字符有序的最小翻转数,那么f(i)和f(i-1)的数目关系要分情况讨论,如果f(i-1)以0结尾,那么f(i)可以以0结尾,也可以以1结尾;相反,如果f(i-1)以1结尾,那么f(i)必须以1结尾因此可以假设f(i)为前i个字符有序且以1结尾的最小翻转数、g(i)为前i个字符有序且以0结尾的最小翻转数那么状态转换方程为:s[i] = 1 时 g(i)=g(i-1)+1 f(i)=min{f(i-1),g(i-1)}s[i] = 0 时 g(i)=g(i-1)原创 2022-04-21 23:58:53 · 110 阅读 · 0 评论 -
剑指offer 专项突破版 91、粉刷房子
题目链接思路设dp[i][j]是第i个房子刷第j个颜色时总共需要花费的价格,那么自然有 dp[i][j] = min{dp[i-1][(j+1)%3],dp[i-1][(j+2)%3]} + cost[i]也就是说 dp[i][j]应该为前一个房子染另外两个颜色的最小值加上这个房子染颜色j的花费class Solution { public int minCost(int[][] costs) { int[][] dp = new int[2][3]; S原创 2022-04-21 23:57:52 · 86 阅读 · 0 评论 -
剑指offer 专项突破版 90、环形房屋偷盗
题目链接思路注意这道题有一个条件是首位不能连续被偷,可以转化为 先求[0,length-2]的最大值,然后再求[1,length-1]的最大值然后二者之中最大值为最后的结果helper函数的参数为数组的起始、结束位置。也就是表明具体在偷窃哪些房屋。需要注意的是此前在空间复杂度为O(1)的做法时,判断i、i-1、i-2的索引是通过i%2,(i-1)%2,(i-2)%2来判断的。但是这道题,我们把起始房间的索引变成1时,因为此时f(1)被放到了dp[0]的位置,所以f(i)应该放入的索引应该是 (i-原创 2022-04-20 21:26:10 · 146 阅读 · 0 评论 -
剑指offer 专项突破版 89、房屋偷盗
题目链接思路假设dp[i]为到第i个房间偷窃的最大值,那么有dp[i] = max{dp[i-1],dp[i-2] + nums[i]}注意i在数组的索引为 i % 2class Solution { public int rob(int[] nums) { if (nums.length < 2) return nums[0]; int[] dp = new int[]{nums[0], Math.max(nums[0],原创 2022-04-20 21:25:39 · 146 阅读 · 0 评论 -
剑指offer 专项突破版 88、爬楼梯的最少成本
题目链接思路对于动态规划类问题最重要的是找出状态转移公式这道题 要上到某一个台阶的代价假设为dp[i] 那么有 dp[i] = max{dp[i-1],dp[i-2] + cost[i])},对于边界情况,dp[0]=cost[0],dp[1]=cost[1] (最开始可以选择第0个或者第1个作为起始台阶,所以要上到第0个或者第1个台阶只需要支付他们自己的费用即可)注意如何节省空间class Solution { public int minCostClimbingStairs(int原创 2022-04-20 21:25:07 · 225 阅读 · 0 评论 -
剑指offer 专项突破版 87、复原IP
题目链接思路这道题的思路在于 某一步要判断 substr(i,i+1) substr(i,i+2) substr(i,i+3) 能不能构成一个合法的ip地址的某一位如果可以的话 那就深入~ 如果都不能 就回溯同时还要判断helper函数何时停止递归class Solution { List<String> result; String str; public List<String> restoreIpAddresses(String s) {原创 2022-04-20 21:02:15 · 163 阅读 · 0 评论 -
剑指offer 专项突破版 86、分割回文子字符串
题目链接思路这道题同样可以分为很多步,我们用index来标明当前应该处理的子字符串开头是什么对于这一步来说 我们应该查找以所有回文子字符串 然后继续调用helper函数~ 递归处理即可class Solution { List<List<String>> result; String str; public String[][] partition(String s) { result = new ArrayList();原创 2022-04-20 21:01:42 · 136 阅读 · 0 评论 -
剑指offer 专项突破版 85、生成匹配的括号
题目链接思路这个题 可以分为N步完成 每一步都有很多选择 所以可以用回溯法来做对于某一步,假设已经输出了m个左括号 n个右括号,那么有如果m > n 那么可以输出左括号也可以输出右括号如果m = n 那么只能输出左括号class Solution { int n; List<String> result; public List<String> generateParenthesis(int n) { resul原创 2022-04-20 21:01:06 · 176 阅读 · 0 评论 -
剑指offer 专项突破版 84、含有重复元素集合的全排列
题目链接思路这个和上个题相比,可能产生重复的条件在于。当前元素和相同元素交换产生的排列是重复的所以在swap之前我们要先判断,该位置的元素是否已经和index交换过了。具体的实现是通过一个哈希表来记录出现过的元素class Solution { List<List<Integer>> result; int[] nums; public List<List<Integer>> permuteUnique(int[] num原创 2022-04-18 20:51:04 · 165 阅读 · 0 评论 -
剑指offer 专项突破版 83、没有重复元素集合的全排列
题目链接思路一具体的全排列其实就是一个分步的问题,第一步可以选择n个元素,第二步选择剩下n-1个,然后再选择剩下n-2个······ 所以可以通过helper函数来传递剩余可选择的数字(subset),具体的处理方式为遍历subset中每一个元素,然后去除,再调用helper方法,之后再把元素放回 class Solution { List<List<Integer>> result; public List<List<Integ原创 2022-04-18 20:50:26 · 166 阅读 · 0 评论 -
剑指offer 专项突破版 82、含有重复元素集合的组合
题目链接思路首先要明白为什么会重复。以[2,2,2,3] 7 为例。因为2重复了三次,所以有可能选择答案的索引为[0,1,3]、[0,2,3]、[1,2,3]之所以会这样是因为可能我们选择了第0个、第1个元素;或者是选择了第0个元素,没选择第1个元素,又选择了第2个元素。对于元素不重复的数组,这样是没问题的。但是对于元素重复的数组,这样就会产生重复的答案所以解决办法为,当我们决定不选择某个元素时,在调用helper函数时,index应该传下一个和该索引元素不同的元素的索引回到我们的例子中,也就是原创 2022-04-18 20:49:49 · 124 阅读 · 0 评论 -
剑指offer 专项突破版 81、允许重复选择元素的组合
题目链接思路一这道题最初的想法是一开始我们寻找组合时都选择在函数中传一个索引index来表明到底选择哪一个元素。但是这道题可以重复选,所以选择在helper函数中用for循环的方式来遍历取值。但是这样可能会产生重复值,比如[2,3,6,7],7。可能会产生[2,2,3],[2,3,2]这样同样的结果。因此需要用一个set来存储结果 class Solution { Set<List<Integer>> result; int[] candida原创 2022-04-17 23:00:56 · 272 阅读 · 0 评论