数据结构
秦枫-_-
慵懒的程序猿
展开
-
重塑矩阵(matlab reshape函数原理)
简单来说就是同样容量的情况下才能转换,否则就输出原矩阵(i,j)对应了矩阵中第i*n+j个数,对应ans中idx/c,idx%cclass Solution { public int[][] matrixReshape(int[][] mat, int r, int c) { int m=mat.length,n=mat[0].length; if(m*n!=r*c)return mat; int [][]ans=new int[r][c]; for(int .原创 2021-08-13 12:08:30 · 1204 阅读 · 1 评论 -
跳跃游戏Ⅳ(bfs+动态规划)
解题思路:题目要求计算从第一个元素跳到最后一个元素最少的操作次数。首先容易想到的是,坐标位于最后一个元素时,结果应为0,因为不用任何操作;对于这个元素紧挨着的左右元素(此时只存在左边的元素),它的操作数是1,因为只需要跳一次就跳到了最后;同理,对于数组里值和最后一个元素相等的那些数,他们的操作数都是1。然后,对于倒数第二个元素,它的操作数前一步已经求得为1,它右边数的结果也已经知道了,是0;它左边的数如果不等于最后一个数,那么它跟最后一个数的距离应为2。这里距离的意思是指操作次数,即跳两次才能到达最后.原创 2021-08-12 18:42:14 · 220 阅读 · 1 评论 -
等差数列划分(双指针or差分)
滑动窗口优化:双指针O(N),i-idx-1之间是一个等差数列,那么求它的等差子数组即可,最小的等差子数组长度为3,数量为len-3+1,最长的等差子数组长度为len,数量为1,那么他子数组的数量也是一个等差为1的等差数列,套用等差数列求和公式,最后i不必从最开始查起,直接跳转到idx-2处 以idx-2为首查等差数列长度即可class Solution { public int numberOfArithmeticSlices(int[] nums) { if(nums.length.原创 2021-08-10 11:21:43 · 148 阅读 · 1 评论 -
超级丑数(巧用记忆数组)
本质上就是将超级丑数ans[]不断跟prime[]中元素相乘得到最新的丑数,那么会出现一个问题:1.如何保证每次放进ans的丑数都是按照次序放进去的?2.如何保证每次放进ans的丑数不是重复值?灵感来源于B站:链接: 超级丑数.解题思路:查找最小丑数可以边历数组,但是不能去重,那么我们通过观察可以考虑到prime[i]跟ans[j]乘过之后就不能回头在用prime[i]*ans[j]了,也就是prime[i]每次在使用完后只用下次乘ans[++j]了,也就是prime[i]最多跟ans[j]乘.原创 2021-08-09 23:34:32 · 129 阅读 · 1 评论 -
访问所有节点的最短路径
关键点就是二进制位来记录某一位结点是否访问 关键就是state[][]数组的设置,然后用队列维护状态class Solution { public int shortestPathLength(int[][] graph) { int n=graph.length; boolean [][]state=new boolean[n][1<<n];//表示访问到当前i结点时,总共访问了多少个结点,二进制i位为1表示i结点已经被访问了 Queue<int[.原创 2021-08-07 23:10:43 · 431 阅读 · 1 评论 -
判断环形数组是否存在循环
这道题解读:首先是 给定的数组一定有环,但是这个环不能是自环且必须是「同向」才合法,因此如果我们在遍历过程中发现存在反向,就停止检查,并且把存在反向环的节点都标记为0,如此以后在遇到这些点就可以直接跳过,因为题目给定的每个点都只有一个唯一的出路,所以不用担心会判断错误具体地,我们检查每一个节点,令快慢指针从当前点出发,快指针每次移动两步,慢指针每次移动一步,期间每移动一次,我们都需要检查当前单向边的方向是否与初始方向是否一致,如果不一致,我们即可停止遍历,因为当前路径必然不满足条件。如果在一个符合题意.原创 2021-08-07 19:08:04 · 284 阅读 · 1 评论 -
蓄水池算法(链表随机节点)
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * ..原创 2021-08-07 00:00:56 · 114 阅读 · 2 评论 -
拓扑排序(解决具有依赖性关系的问题)
拓扑排序是对一个有向图的顶点进行排序。它关心的是图中各个顶点的连接关系,这种连接关系也叫拓扑关系,因为它不关心各个顶点的位置与距离。应用:在一个有向无回路图中,要求对所有的节点进行排序。先统计所有节点的入度,对于入度为0的节点就可以分离出来,然后把这个节点关联的节点的入度减一。一直做改操作,直到所有的节点都被分离出来。如果最后不存在入度为0的节点,那就说明有环,不存在拓扑排序,也就是很多题目的无解的情况。下面是演示过程。举例:力扣113 课程顺序解题思路:由题目给出一个有向无回路图原创 2021-08-04 18:43:37 · 1446 阅读 · 2 评论 -
二叉树的垂序遍历(基于前序遍历的升华)
核心思路:自定义排序每个节点有三个属性:值val,行坐标row,列坐标col1、先按列排序,从小到大;2、列相同,再按行排序,从小到大;3、行相同,按值的大小排序,从小到大。所以我们有两种实现思路:用双哈希表或者结构体自定义排序双哈希表:一个表存储列,一个表存储行,用数组每次记录数据,然后对数组进行自定义排序/** * Definition for a binary tree node. * public class TreeNode { * int val; * .原创 2021-07-31 12:16:20 · 223 阅读 · 2 评论 -
最长递增子序列&&得到子序列的最少次数
基础:求一个序列的最长递增子序列二分+贪心:最长子序列的长度一定小于等于数组的长度,那么使用二分法,在遍历数组过程中,找到合适位置插入当前数据,如果当前查找位置比nums[i]小那么nums[i]应该放在当前位置的右侧,反之当前位置>=nums[i],那么右侧的范围应该缩小,使得当前较大位置数据替换成nums[i],如此我们可以得到最长递增子序列class Solution { public int lengthOfLIS(int[] nums) { int []mm=new原创 2021-07-26 22:38:55 · 302 阅读 · 1 评论 -
从相邻元素对还原数组
题意理解:就是把原来的数据按照相邻一对儿一对儿的分割成一个二维数组,然后打算顺序,让你还原解题思路:我们可以试用哈希表记录每个元素的相邻元素,当遍历完二维数组后,通过识别相邻元素个数即可得出首尾元素,首尾元素的相邻元素个数都为1,那么题中说多种顺序下,返回任意一个顺序即可,即我们确定一个首元素后,接下来就可以通过利用哈希表记录的相邻元素去依次往右添加元素注意每个数的相邻元素最多只有两个,那么当记录的第一个相邻元素不等于某个元素的左侧元素时,它就是这个元素的右侧元素,当等于左侧元素的时候,那么右侧元.原创 2021-07-25 13:11:12 · 93 阅读 · 1 评论 -
检查是否区域内所有整数都被覆盖(遍历一次,区间相消即可)
根据题意,就是要在ranges中找到能包含left和right的所有区间那依次遍历ranges所有区间,当[[start],[end]]跟[[left],[right]]没有重复区间时直接跳过当[[left],[right]]完全包含了[[start],[end]],把start,end区间消去然后判断left,start-1&&end+1,right当[[start],[end]]包含[[left],[right]]的部分区间分为两种情况:一种是包含了[[left],[right.原创 2021-07-23 16:17:22 · 228 阅读 · 1 评论 -
绝对差值和
class Solution { final int mod = 1000000007; public int minAbsoluteSumDiff(int[] nums1, int[] nums2) { int []rec=new int[nums1.length]; System.arraycopy(nums1,0,rec,0,nums1.length); Arrays.sort(rec); int maxn=0,sum=0; for.原创 2021-07-15 00:09:06 · 567 阅读 · 1 评论 -
扫描线算法(天际线问题)
扫描线的核心在于 将不规则的形状按照水平或者垂直的方式,划分成若干个规则的矩形。class Solution { public List<List<Integer>> getSkyline(int[][] buildings) { List<List<Integer>> ans=new ArrayList<>(); List<int []>bu=new ArrayList<int []>();.原创 2021-07-13 23:28:08 · 334 阅读 · 1 评论 -
h指数:求数组中满足有h个数>=h,n-h个数<=h的最大h
排序遍历:结果必然是0<=h<=n其实两个条件等于一个条件,随意设一个数组,排序后,假设某一位数他是数组中第h个数,且这个h满足我们想要的结果,那么如果它和后面有h个数大于等于h,前面的数必然小于他本身,且前面有n-h个数,所以融合两个条件为一个,h从0开始递增,我们从数组最后一位最大的数向前遍历,h表示当前数(不含自身)后面有h个数>=h,如果num[i]>h,则我们发现h+1也是满足结果的,则h++替换h,同时继续向前判断,直到h不能递增为止class Solution {.原创 2021-07-11 12:07:11 · 383 阅读 · 1 评论 -
并查集解决图论问题(连通性及有无圈存在)
题目中确定给的是连通图,那么根据图论知识树的等价条件为m=n-1,所以很明显数组中只有一条边是答案,同时只要找出来图中的一个圈就能得到答案,树是无圈连通图,那么可以用并查集思想解题回想图论找出最小生成树 有避圈法和破圈法,本题用避圈法思想遍历数组,对于每一条边的两个点 ,在这条边之前构造的图中,如果两点已连通,加上这条边就有圈,就必然不是树,所以这条边就是答案如果两点不连通,加上这条边则为树,继续下去找最大树class Solution { public int[] findRedunda.原创 2021-07-01 22:35:14 · 391 阅读 · 1 评论 -
串联字符串的最大长度(位运算)
class Solution { public int maxLength(List<String> arr) { List<Integer> res=new ArrayList<>(); res.add(0); int ans=0; for(int i=0;i<arr.size();i++){ String s=arr.get(i); int cur=0; for...原创 2021-06-19 13:29:00 · 87 阅读 · 1 评论 -
四平和定理解决一个数的完全平方数组成个数
example:求组成一个数的完全平方数的最小个数class Solution { public int numSquares(int n) { if (isPerfectSquare(n)) { return 1; } if (checkAnswer4(n)) { return 4; } for (int i = 1; i * i <= n; i++) {原创 2021-06-14 15:02:51 · 100 阅读 · 1 评论 -
前缀和大集合(子数组=target问题,子矩阵=target问题)
含有相同数量的0和1,就意味着这样的子数组长度是这个区间和的二倍,那么可以推导出这样一个公式:sum[cur]-sum[pre]=2(cur-pre) =>sum[pre]-2pre=sum[cur]-2cur; sum[i]表示前i个元素和同时cur-pre>=2;所以判断的时候从i=2开始判断, 用哈希表存放所有元素的sum[pre]-2pre和对应子数组长度,第一个应该是(0,0),后续只要判断是否存在2*sum[i]-i,如果存在就结果=当前长度-map.get(k)c.原创 2021-06-07 12:29:27 · 134 阅读 · 2 评论 -
巧用图论知识解数组汉明距离总和
其实就是图论里边的偶图,例如:当只有所有数都是0或1的时候,0和1看成两个分支 0为X分支 1为Y分支 求边数,0和1连边才有汉明距离,同一分支不能互连 按位运算把所有nums[i]某一位的0和1看成两个分支 0为X分支 1为Y分支 求边数,0和1连边才有汉明距离,同一分支不能互连class Solution { public int totalHammingDistance(int[] nums) { int res=0; int []digit=new .原创 2021-05-28 09:58:39 · 114 阅读 · 1 评论 -
反转每对括号间的子串
思路:遇到括号内问题就首先想到利用栈去解决从最内层开始,一层一层反转,那么之前遍历的字符串依次存入栈中,没反转内层依次,将前一次读取的字符串添加上,反转时刻就是当遇到‘)’的时候,而放入栈中的时刻就是遇到‘(’的时候。class Solution { public String reverseParentheses(String s) { Stack<String> stk=new Stack<>(); StringBuffer res=new St.原创 2021-05-26 11:11:34 · 157 阅读 · 1 评论 -
使所有区间的异或结果为零需要修改的元素的最少数(DP)
class Solution { public int minChanges(int[] nums, int k) { int maxn=1024; int [][]dp=new int[k][maxn]; int []g=new int[k]; for(int i=0;i<k;i++){ Arrays.fill(dp[i],0x3f3f3f); //g[i]=0x3f3f3f; } for...原创 2021-05-25 13:26:45 · 122 阅读 · 1 评论 -
利用归并法求数组中的逆序对
关键在于合并的过程中怎么求解逆序对的数量,合并过程中需要将乱序的[left,mid]和[mid+1,right]元素排好序,此时[left,mid]和[mid+1,right]均排好序的情况下,那么如果num[idx1]>num[idx2]代表[idx1,mid]之间的所有元素都>num[idx2],跟num[idx2]组合都是逆序对,此时求解出来的逆序对数量是 mid-idx1+1而因为[left,mid]和[mid+1,right]还并未合并,所以前后两组元素顺序并未改变,这样算法..原创 2021-05-24 16:26:53 · 705 阅读 · 3 评论 -
区间DP问题(移除游戏+打印机问题)
class Solution { public int strangePrinter(String s) { int [][]dp=new int[s.length()][s.length()]; //for(int j=0;j<s.length();j++){ **从前往后打印** // dp[j][j]=1; // for(int i=j-1;i>=0;i--){ // if(s.charAt(i)==s.c..原创 2021-05-24 11:31:24 · 82 阅读 · 1 评论 -
与数组中元素的最大异或值(字典树)(小于等于某元素的最大异或值)
class Solution { class Tree{ Tree []son=new Tree[2]; } Tree root=new Tree(); void establish(int x){ Tree roo1=root; for(int i=30;i>=0;i--){ int t=x>>i&1; if(roo1.son[t]==null)roo1.son[t]=new.原创 2021-05-23 20:33:53 · 103 阅读 · 3 评论 -
数学博弈游戏
因为s=0,那么一开始爱丽丝就赢了 与假设矛盾了class Solution { public boolean xorGame(int[] nums) { int sum=0; for(int i=0;i<nums.length;i++){ sum^=nums[i]; } return sum==0||nums.length%2==0; }}原创 2021-05-22 10:45:25 · 339 阅读 · 2 评论 -
前K个高频单词(hashmap,priority使用以及自定义排序)
哈希表class Solution { public List<String> topKFrequent(String[] words, int k) { HashMap<String,Integer> map=new HashMap<>(); for(String ch:words){ map.put(ch,map.getOrDefault(ch,0)+1); } List<String> res.原创 2021-05-20 10:29:03 · 96 阅读 · 1 评论 -
形成两个异或相等数组的三元组数目(前缀和)
a = b 等价于 a ^ b = 0。那么我们的问题就转换为了arr[i] ^ arr[i+1] ^ … ^arr[k] == 0,可以看到与j的取值无关,只要j∈(i,k]j\in(i,k]j∈(i,k]即可满足条件。那么我们就将循环从三层循环降为两层循环,i和k,使用x计算arr[i] ^ arr[i+1] ^ … ^arr[k] 。如果 sum = 0,那么这种情况下就有 k-i个满足条件的(i,j,k)。class Solution { public int countTripl.原创 2021-05-18 12:17:39 · 75 阅读 · 1 评论 -
判断二叉树的堂兄弟节点BFS+dfs
DFSclass Solution { int x, y; int depthX, depthY; TreeNode fatherX, fatherY; public boolean isCousins(TreeNode root, int x, int y) { this.x = x; this.y = y; getNodeDepthAndHisFather(root, null, 0); return (.原创 2021-05-17 13:06:08 · 192 阅读 · 1 评论 -
数组中两个数的最大异或值(字典树||前缀树)
class Solution { class Tree{ Tree []son=new Tree[2]; } Tree root=new Tree(); void construct(int x){ Tree child=root; for(int i=30;i>=0;i--){ int t=(x>>i)&1; if(child.son[t]==...原创 2021-05-16 14:35:19 · 150 阅读 · 1 评论 -
剑指offer41 数据流中的中位数
考虑使用两个优先队列实现,一个大顶堆B放较小的一半元素,一个小顶堆A放较大的一半元素,,然后比较两者元素数量,同时最开始从B放入元素,相等就A从B中拿走最大的元素,不等就放入A,B从A中拿走最小的元素,如此两者元素数量差维持在1或0,而且这样保证了B的顶元素一定是小于等于A的顶元素,因为从本质上看,B获取元素每次都是从A中拿走最小值,而放入B的时候又同时把它的最大元素给了A。这样造成的结果就是A.size()>=B.size(),最后只要看两者大小,相等取顶元素平均,不等取A顶元素。class M.原创 2021-05-14 18:22:48 · 63 阅读 · 1 评论 -
二叉树的序列化和反序列化
序列化就是把二叉树转化成一个字节序列,反序列化就是将一个字节序列重建成二叉树为什么要序列化? 这样可以使得二叉树的状态信息转换为可以存储或传输的形式,所以你可以认为序列化一个二叉树是编码的过程,而反序列化则是解码的过程什么时候需要序列化?当你想把内存中的对象保存到一个文件中或者数据库中的时候;当你想用套接字在网络上传送对象的时候;当你想通过RMI传输对象的时候;二叉树的序列化本质上是对其值进行编码,更重要的是对其结构进行编码。这里,我们选择先序遍历的编码方式,public class .原创 2021-05-13 17:35:16 · 155 阅读 · 2 评论 -
用dfs或动态规划实现正则表达式匹配
正则表达式是通常被用来检索、替换那些符合某个模式(规则)的文本,即记录文本规则的代码。dfs方法class Solution { public boolean isMatch(String s, String p) { if(p==".*")return true; return getmatch(s,p,0,0); } public boolean getmatch(String s,String p,int m,int n){ if(p.len原创 2021-05-12 21:45:01 · 128 阅读 · 1 评论 -
前缀异或he前缀和(区域检索)
class Solution { public int[] xorQueries(int[] arr, int[][] queries) { int []asc=new int[arr.length+1]; for(int i=0;i<arr.length;i++){ asc[i+1]=asc[i]^arr[i]; } int []res=new int[queries.length]; for(int i=0;i<qu..原创 2021-05-12 11:35:41 · 179 阅读 · 1 评论 -
数组剔除元素后的乘积
其实本质就是用两个res数组,分别维护 i 左侧、右侧的乘积和。class Solution { public int[] constructArr(int[] a) { if(a.length==0)return new int[0]; int []res=new int[a.length]; int total=1; int []res1=new int[a.length]; res1[0]=1; int []res2=new int[.原创 2021-05-11 15:22:19 · 82 阅读 · 1 评论 -
解码异或后的排列延伸(数学问题)
接着利用异或的性质即可得出原数组class Solution { public int[] decode(int[] encoded) { int []res=new int[encoded.length+1]; int n=encoded.length+1; int first=0; for(int i=1;i<=n;i++){ first^=i; } int dfirst=0; for(int i = 1; i <...原创 2021-05-11 11:08:26 · 100 阅读 · 1 评论 -
java(Array.sort())原理
原创 2021-05-10 12:12:43 · 82 阅读 · 1 评论 -
打印二叉树中和为目标值的路径
class Solution { List<List<Integer>> res=new ArrayList<>(); List<Integer> path=new ArrayList<>(); public List<List<Integer>> pathSum(TreeNode root, int target) { int count=0; dfs(root,targe.原创 2021-05-09 12:25:33 · 160 阅读 · 2 评论 -
母亲节做个花----制作 m 束花所需的最少天数
class Solution { public int minDays(int[] bloomDay, int m, int k) { int nums=m*k; if(bloomDay.length<nums)return -1; int low=1,high=Arrays.stream(bloomDay).max().getAsInt(); while(low<high){ int mid=(low+high)/..原创 2021-05-09 11:18:43 · 98 阅读 · 1 评论 -
二分法+回溯+剪枝解决工人完成所有工作最短时间问题
class Solution { public int minimumTimeRequired(int[] jobs, int k) { Arrays.sort(jobs); Collections.reverse(Arrays.asList(jobs)); int low=jobs[0],high=Arrays.stream(jobs).sum(); while(low<high){ int mid=(low+high)/2;...原创 2021-05-09 00:04:21 · 173 阅读 · 4 评论