0%

21年10月-22年5月

[toc]

刷题日记

😉 😢 😆 😋

[2022-05-09]

  • 给一个图,找入度为n、出度为0的唯一点,最少可以通过3n次查找,从0到n通过遍历a->b,逐步排除不可能的选项,最终只剩1个,然后再通过2次n确认入度和出度。 😄

2022-05-02

  • s.indexOf(i, “}”) 可以快速得到下一个

2022-04-09

  • 要求ty通过反复减tx,要减到小于等于tx的话 那么就是ty%tx的值
  • 对于自己推导中间过程比较麻烦的题目,就直接写个sout打印中间能很快观察到问题所在
  1. 先写个超时的答案
  2. 打印中间结果,看下哪里浪费了
  3. 对浪费的步骤做优化

2022-0405-0406

  • 求1个数字N是否为质数的一个简单方式: 只遍历i=2到i=根号(n),然后确认能否被整除即可。
  • 优化1: 求二进制1的个数,没必要手动求解, 直接用Integer.bitCount()即可
  • 优化2:质数如果总数比较小,可以直接手动大表,这题里最大数字范围为19 ,那么质数可以直接打表得到
  • 找到一个最小高度的树的根节点,可以用拓扑排序,从最外围往内部逼近

2022-04-01

  • n如果是整数,可能直接越界,需要提前强转
  • 如果状态条件种要求不能连续的问题, 考虑状态是否多加一个,这题的状态方程就是,dp[当前位置][颜色][上一个点是否是该颜色]

2022-0329-0330

  • 知道很多点的大小关系,求整个的大小关系,可用拓扑排序
  • Stringbuilder.reverse() 会导致自身翻转,所以切忌不要对搜索变量stringbuidler做翻转,要么记得转回来

2022-03-28

  • 如果二进制a都是0、1交替的,那么a ^ (a>>1) 则会变成除前置0外,全是1
  • 如何判断某个二进制a全是1组成?a&(a+1)==0, 则说明全是1
  • 多个字符串编码成1个字符串,可以用非ascii码的字符做分隔符(char)257
  • 涉及次数问题的题目,且题目次数一定小于某个总数,则可以考虑计数排序

2022-03-27

  • 涉及数字出现次数,求里面某几个特别的次数的数字时,记得使用分类,即想办法把他们分成不同的组,再分别做异或即可。
  • x&(-x)是x=110100变000100, x&(x-1)是x=110100变111000
  • 如何判断一个图是否是1课树?
    方法1:首先保证边数=节点数-1,然后用bfs保证所有点相连
    方法2:并查集,合并过程不能出现2个根节点相同(说明树内循环连接了),合并完成要求只有1个根节点

2022-03-26

  • 一个数组,如何求去掉每个位置时的数组中的最小值
    维护最小值和第二小的值即可
    注意,当更新最小值的时候,同时需要更新第二小的值!

2022-03-24

  • 自定义迭代器注意点:迭代器特点,无论是hasNext还是next,都需要先找到下一个有效的点, 再去判断,而且是通过while循环查找。

2022-03-23

  • int[] 截断成list,可以先转list,再用subList截断.
    ret.subList(0, k);
  • 寻找num在list中的位置:Collections.binarySearch(list, x);
  • 用常量空间判断数组是否是二叉搜索树的先序?
    遍历每个点,只测试右边方向的正确性

2022-03-21

*1个有序数组,求2个数字的和满足target,可以用双指针最左和最右,然后根据大小情况移动左边或者右边。为什么不可能往回走?因为你之前已经走过的点,能确认右边那个位置是无法满足的

  • 中序遍历迭代树, 注意走下一个点时,要么右儿子为空往上走,要么走右儿子后,还得往左边一直走到底,才算是下一个点

2022-03-19

  • list[]初始化,直接for循环最简单

2022-03-18

  • 一个java-stream的小点: 按照key分组并统计每组key的数量
    Map<String, Long> strMap = Arrays.stream(strings)
    .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
    即groupingBy(key->key, Collectors.counting())
    如果记不起来,马上改成用stream().foreach或者直接循环即可

2022-03-17

  • 2个单词在词典中的最短距离,最好方式是用双指针,如果i1<i2,则i1++,这样子

2022-03-15

  • unicode形式的字符,尽可能用character对象,一个字符可能是多个字节表示,因此不能用数组下标来简单处理这类字符的哈希问题

2022-03-14

  • 如果求解二叉搜索树的第k个点,要求频繁查询的性能,则事先统计每个子树的节点总数量,即可快速判断在左边还是右边。(如果不平衡则要平衡树)
  • p、q最近公共祖先问题,可以不一定用父亲数组遍历2次, 而是用 该树是否包含p或者q的布尔值结果,通过先序遍历,找到第一个左右两边都有p\q的情况(也包括自己是p或者q)

2022-03-13

  • 如果希望使用双端队列而不是栈,请不要用Push和poll了,就用first和last两个语义处理,避免混乱
  • LinkedList push 施加在list头部. 等同于addFirst。 add 是加在list尾部。
  • 如果一个式子中只有+号和-号,无括号,则直接将-号后的数字取负即可

2022-03-09

超期优先队列应用

2022-03-08

  • 如果题目只需要你返回true或者false,即不需要中间所有结果,则考虑到一些情况可以不用过分担忧,如果有影响,则可能直接返回true了
  • 完全二叉树的节点是否存在,可以用位运算来表示,往left走代表0,往right走代表1.

2022-02-20

  • 回文串最简单的判定s = 翻转(s), 可以考虑字符串哈希等东西,或者KMP前缀后缀判定优化
  • 字符串哈希,第0位数字不可为0,至少要有数字,因此不需要做s.charAt(i) - 'a’的操作

2022-02-19

  • 因此股票买卖,要考虑持有或者不持有,然后通过买入扣钱以及卖出加钱来计算
  • 字典树问题,如果是考虑单词“全匹配”,则必须要在字典树末尾补充isEnd标志。

2022-02-18

  • 字符串只有10时,做substring和map.hashcode的时间都是可接受的,可直接用
  • 子序列对应x进制的滑动窗口问题中,你可以先整体右移动,然后截断第一个位,再加上最后一个,即可。
  • 如果窗口大小是的2的倍数,则可以继续用位运算,只不过偏移数量要变化
    7897843fc21e6aee738cf9853605db09378a0ef0
  • 对于长度固定的窗口,你可以先预处理窗口剩1个, 然后再开始,避免重复判断
    8b5ec292b0898702f3d8c0c1eb08127488982cb7

2022-02-17

  • 如何O(h高度)遍历二叉搜索树? 利用栈,每次把左左左放入,然后出栈时,右儿子放入后继续左左左放入
  • 几个数字怎么排列乘一个数字后最大, 只要满足a+b>b+a,那么a就放在前面即可。
  • 字符串去除前置0的操作:.replaceAll(“^(0+)”, “”)
  • 字符串a+b和b+a做比较觉得不好,可以改成long整数,分别乘高x10位加另一个数字来比较

2022-02-16

  • 一个节点的祖先和后代节点集合, 一定包含在他父节点的祖先和后代节点集合
  • 可根据各节点的祖先和后代节点数量,确认是否是祖先关系,父亲节点是数量最靠近自己的
  • 后面暂时不做每日一题了,直接按面试高频题进行练习。

2022-01-27

  • 注意javaStream.filter中,是满足条件的留下, 而不是剔除。
  • 边界比较麻烦的问题,要自己写一下UT用例,覆盖边界场景,再写代码,这样就算错了,给人留下的印象也会很不错

2022-01-26

  • 快速计算list或者map.values()的最小值方法:Collections.min(collection)
  • 滑动窗口遵循下面的写法最简单:
  1. 只写一个while循环,即只默认循环加right
  2. 每次都直接把right放入窗口。
  3. 当窗口不满足,则移动左节点直到满足。如果左节点大于右节点,结束左节点的移动。
  4. 计算当前窗口结果。左大于右时,要能算为0
  5. right++

2022-01-24

  • 求List的int最大值时,需要先mapToInt, 再求最大值。 如果最大值可能不存在,要用orElse设置默认值
  • 分子/分母的整除对象做哈希键时,需要做4种处理
  1. 分子必须保证为非负数(如果小于0,则上下都乘-1即可)
  2. 需要求出gcd进行最小约分
  3. 用最大边界来表示这个二维值:(分子/gcd) * 最大边界 + (分母/gcd)
  4. 分子为0,那就简化成(0,1), 分母为0,那就简化成(1,0)

2022-01-22

  • 每次提交代码前,必须看一下中间10^5范围的中间结果是否可能超出int范围。

2022-01-21

  • 对链表题排序, 注意每次排序完部分链表时, 需要更新最后一个节点的next!
  • 如何对链表做排序,且空间复杂度最小?使用迭代法的归并排序,即自底向上的归并排序。那么就很容易了
  • 怎么划分2个需要合并的列表?提前把尾部设成null
  • 合并两个链表时,可以弄一个局部头节点,这种不算空间复杂度,因为是局部变量, 后面会释放掉。

2022-01-20

  • 无法搜索的博弈论问题,尝试找规律, 当先手选某一步,之后大概率会陷入某类循环中,直到出现胜负。
  • 不能很快得到公式时,不妨写土方法遍历1下看能否满足循环序列。
  • 短时间想不到的博弈论问题,直接放弃,博弈论还是比较脑减急转弯的

2022-01-19

  • 如何避免构建初始滑动窗口的麻烦?可以往右边遍历时,到达某一个边界,才开始删除,就不用构建初始窗口那么麻烦了。
  • 用迭代模拟递归核心原理:
  1. node局部变量,指代dfs方法中的node入参。
  2. 当前node还有用,但需要往下搜索时,把自身入栈,再更新node局部变量。
  3. 当stack.pop时,说明已经从dfs(left)或者dfs(right)中走出来了。 则按照递归代码,选择继续走right入栈,还是直接打印自身。
  4. node=null指代什么?指代必须要用stack.pop,即开始回溯了。当你试图回溯时,不可自己做node=node.right的操作, 而是要通过stack.pop处理

2022-01-17

  • 因此动规适用于单个结果,不适用于动规路径或者排列。如果需要求路径组合或者一定条件的排列组合,请使用记忆化搜索而不是动态规划。因为记忆化搜索时,只有成功搜索到底部,才会得到记忆化结果
  • 链表首尾不断相连的解法: 如果涉及从后向前处理的链表,考虑反转链表再操作。 对于中点,使用快慢指针。

2022-01-16

  • 感觉不好计算最终数组有几个位置的话,不如直接用list,最后toArrya(new xxx[0])即可
    return results.toArray(new String[0]);
  • 问题是分配问题,但是却需要你计算一个某最大长度结果,则可以考虑二分法,固定最大长度,再分配。

2022-01-15

  • 位运算问题,可以考虑“各位的数量",例如只有1个数字是1个,其他都是3个3个出现,那么可以从每位的1的个数,推断出那个数字(其他肯定要么是1的3倍或者0倍,加起来)
  • 上一个状态集合是[00,01,10,11],和数字[0,1]碰撞后,得到一个新的状态集合[x,y…],则可以画出一个卡诺图, 上一个状态集合看作a\b两个门, 数字[0,1]看作c这个门,从而得到a和b的新状态电路情况
    a8eac0b3823f887071474d90e16e46f2475973e5

2022-01-14

  • 有时候要求满足复杂规则情况下,求最优结果,则可以考虑拆分成多种规则,取每个位置的最大值或者最小值
    9fc32c38f70bff95f29aa46ba21db777a3362488

2022-01-13

  • 当从i往右滑动到j时,整个过程要求都满足区间和[i, k]大于等于0时, 一旦有[i,j]不满足, 则[i,j]中的任一点都无法作为起点, 因为[i,i]肯定满足>=0,则[i+1,j]肯定变得更小了,以此类推(或者说[i,xxx]这个前缀和肯定都大于0,得到中间任一位置都无法满足)

2022-01-11

  • 根据障碍数n,计算出一个能围住的最大格数max,如果a能bfs搜到的点大于max,说明没围住。 如果小于,则肯定围住了。
    网格中,障碍个数n能围住的最大格子个数max= n*(n-1)/2
  • x=1000000,y=1000000, xy不会超Long, 但是(x+1)(y+1)可能会超

2022-01-10

  • 差距某个字母才算相邻的单词相邻问题,可以使用虚拟节点求解。(同理可以作用到数组相邻问题上)
    例如abc可以和bc、ac、ab*这三个虚拟节点相邻。
    其他一样处理, 这样就可以直接连起来
    还要维护id到单词、单词到id的2个映射map。
  • 双向bfs可以降低空间消耗,但是不能降低过多的时间复杂度
  • 力扣不支持bigInteger。如果在35位范围内,可以尝试使用Double表示大整数。如果长达几百上千位,就只能自己写string大整数加法了。

2022-01-08

  • 力扣竞赛,示例的正确答案在右边,不要看错了
  • 可以先写一些用例,在跑,减少罚分,养成习惯
  • 给你一堆固定长宽矩形的左上顶点, 让你判断某个点是否被任一矩形包含,则 可以反向前缀和, 求这个点的左上矩形区间内是否包含矩形顶点即可
  • 前缀和别写错,注意要-1的都是左上角顶点坐标
    fd9f505ce39b64eaebad16f0e4445fe305526913

2022-01-06

  • 组合数C(n,m)可以用杨辉三角求, 杨辉三角的n行m列等同于C(n,m)

2022-01-05

  • 遍历小写字母, 用for(c = ‘a’;c<=‘z’;c++)而不是for (j = 0; j < 26; j++) { (char)(j+‘a’)}
  • 能用spilt分割就用spilt,别自己分割,容易搞错
  • 当给树添加新的指针,让你做常见遍历,却要你用常数空间时,一定是利用新指针当作线索来做遍历,避免了用栈或者队列。

2022-01-04

  • 树的搜索, 用迭代替代递归的关键点:
  1. node局部变量等同于dfs(Node node)里的node入参
  2. while(node = node.left) 等同于走dfs(node.left)
  3. 取栈顶, 等同于if(node==null) return的这个边界
  4. node.right 入栈, node = node.right 等同于dfs(node.right)
  • 要求空间复杂度为1的树中序遍历, 考虑利用左子树的最右节点的right空闲指针,指向自己,来快速跳转
  • 二叉搜索树寻找问题节点, 直接遍历得到list,然后排序,就能找到问题节点了。

2022-01-03

  • 矩阵最大面积问题,提前想到单调栈,固定自身高度h,左右扩展。
  • 计算星期几、日期相关题目, 统一用减去1970年12月31日的方式,拿到时隔多少天, 用天数去判断
  • 子集问题,直接dfs,不要想着骚操作搞for循环,太容易写错了。避免重复,就是那个原则“必须连着选相同的,不能跨着选相同的”

2022-01-01

  • 如果是单调栈的题目,最终肯定只需要使用栈头的元素。 如果你发现需要遍历栈中所有元素,导致高度和宽度全在变化导致无法计算, 可以看一下是不是改变计算思路,固定自身为某个高度,而不是去寻找前面的某个高度。
  • 把上一组n阶的格雷码集合 都在头部加一个1, 然后倒序加进来即可。(可以理解为先头部加个1跳进去,然后反向走一遍,就肯定能保证走回去了)

2021-12-30

  • 不要看到总数为n,分组长度最大为n,就认为自己的双重for循环可能有O(n^2)的复杂度。
    对于会提前结束/退出判断的情况来说, 双重for可能最多就O(n),循环就会结束了

2021-12-29

  • a+b+c=d的等式问题, 可以转化为a+b=d-c问题
  • 4个点的复杂滑动窗口问题, 可以只滑动中间点, 左边当区间复用历史结果, 右边做遍历。
  • 从某序列变成某序列的“最短编辑距离”问题, 可以考虑动态规划, 判断从子序列A变成子序列B时,能通过做哪些动作实现部分匹配,再判断剩下子序列a和子序列b的最短距离即可。
    b126300997a64998cce44f429188d3f512dbbed6

2021-12-28

  • List<int[]> result如何转int[][]? result.toArray(new int[0][0]);
  • 问你某某走法的数量,却要求空间限制,无法动态规则,则考虑组合数。
  • 组合数快速解法:
1
C(8,3) = 8 * 7 * 6 /(3 * 2* 1) =( ((((6 / 1) * 7) / 2) * 8) / 3)

2021-12-27

  • 当数量很大,但是数值范围很小,却要你做二分、排序或者区间统计时,优先考虑直接用数组做计数排序/计数前缀和。

2021-12-26

  • 快速只保留末尾的1,其他全置0: b &(-b)
  • 快速剔除末尾的1: b &(b-1)
  • 全排列问题, 直接搜索每个位置能放谁,从0开始遍历+vis数组
  • 重复问题的剪枝:只能连续插入重复的数字,不能跳跃着放重复数字。因为跳跃了的话,前面完全可以搜过一样的情况

2021-12-23

  • 遇到特定长度的子串/子数组是否重复/已存在的问题,可以考虑用字符串哈希

2021-12-20

  • 二分的最大right记得想清楚,不确定的话直接Integer.MAX_Value就行

2021-12-19

  • 问你最少替换几个数字, 可以变成递增序列, 其实 可以变成“求出最长递增子序列后, 剩下的就是要变的数字”。 或者说替换几个东西,可以变成xxxx, 是否可以改成求 最长的xxxxx,然后剩下的就是要改变的东西
  • 如果设计key-value的value二分, 不要试图用treeMap,因为treeMap是基于key排序的。 做更新操作会恶心死自己,不如直接基于key二分,然后判断value

2021-12-14

  • 数独判断的问题记得先写针对区间的check函数,再判断,会简化很多操作。
    9c00e5b295a063c590a4e969521709d8d673cdb4

2021-12-13

  • 旋转数组二分问题,每次找有序的那段,再去判断
  • 旋转数组如果有重复数字,提前处理左右边界都相等的情况,都+1和-1,这样就省了很多复杂场景了

2021-12-12

  • 滑动窗口求最大值问题时,不要忘记求初始窗口时的最大值更新。

2021-12-11

  • 排序过程如果涉及索引,可以考虑弄一个索引i的数组,对i做排序,不需要带着索引弄个二维数组很麻烦
  • Arrays.sort如果要对int[]数组自定义排序, 应该使用Integer[]而不是int[]数组。
  • 如果滑动窗口如果发现删除点的操作比较麻烦,可以尝试事先利用数组特性预计算一些前缀和等数据,提前算好那个区间的值,而不需要去考虑移动时点的更新。
  • bfs时,一定要记得第一个入队的点需要设置vis[x] = true,这个很容易漏!

这下面的是从旧往前, 而最新的都改成了新的放上面

2021-10-07

  • 复杂字符串解析问题, 尽可能避免边解析边计算,可以分成2步来做,先解析成N个字符串,再依次判断和计算。
  • 并查集问题,涉及边界相连的情况,可以将边界认为是一种集合。
  • 二维点问题,尽可能用index = getIndex(y,x) 获取二维索引, 避免大量二维数组操作, 用InArea(y,x)方法减少判断代码。

2021-10-08

  • 相连、成环问题,都要想到可能和并查集有关
  • 对于复杂的模拟过程题目,一定要自己在纸上把几种情况列出来,切忌脑测然后想出一个完全不合理的解决思路。

2021-10-09

  • 字典树的使用和查询过程,切忌偷懒,不要漏了走到null节点结束查询的情况。
  • 迷宫理论: 总共n种位置,走了2n步,则一定是死循环,无法走出(在博弈题里即平局)
  • 动态规划,记得步长或者回合数是可以当状态的, 不要漏了这个,不要死脑筋只想着做状态压缩
  • 位图状态压缩,力扣题几乎都是16位情况的压缩, 几乎不会出现32位以上的,超过这些,则考虑是否可以不需要记录走过的点之类的。

2021-10-10

  • 一组数字,如果只能加和减任意x,且要求最终相等, 他们必定互相之间的差值是x的倍数
  • 求和问题、绝对值问题,注意最好先自己用数学公式推导一下,更容易快速理解思路,切忌胡思乱想

2021-10-11

  • 交替复制的问题,可以使用双指针来做
  • 优先队列:a是上面的点,b是下面的点(儿子节点),(a,b)返回大于0的时候,则交换
  • 涉及排序变化,由数组A变成数组B的问题, 确定一下是否存在 ”稳定排序“,即不会跨相同数字变动, 能确定的话,就可以确定数组B中每个数字是由哪些位置的数字变化而来, 从而找到突破口

2021-10-15

  • 什么情况下Arrays.stream(数组)之后不需要boxed()? 即不是int[]、long[]这种需要转包装类型才能变成list的情况
  • 记忆一下.collect(Collectors.toList()))
  • 滑动窗口, 建议先用for循环移动右边, 确定右边的位置后,再用while移动左边找到满足条件的左边界, 这样可以简化很多判断
    d987e1f51885cc3c4a0c5d2b059a8e2ca5633145

2021-10-16

  • 数组A和数组B个数相同,B里的每个值要通过+1、-1变成A时,需要的次数为 ”AB分别排序后,每个i位置的Math.abs(a[i] - b[i])总和“
  • 即使心态不好, 也要仔细审题加看例子,不能不理会用例,错过用例很可能就理解错误导致gg
  • 边比较少点比较多的情况时,如果要求最短路径, 则用bfs,不需要djkstra
  • bfs求最短路径时, 只需要newDis < dis[node],再入队即可,且不需要做很多的vis判断。记住这个bfs求最短路
    3c84111fe71f4a886bab0bd1b28816389c78b017

2021-10-17

  • n个数小于16的时候, 如果题目涉及选或者不选,那么是可以直接暴力枚举出所有的情况的,不需要用dp缓存之类的。
    利用下面的代码求某一位怎么用上,不需要vis数组或者while除2啥的很麻烦的那种
1
2
3
4
5
6
for (int j = 0;j<len;j++) {
// 说明那个数字做过亦或,不需要vis数组
if ( (i & (1<<j)) > 0) {
// 选中了nums[j], 拿nums[j]做对应的操作;
}
}
  • 某DAG点如果可以重复走,那么当你走到某个位置时,其最小路径和次小路径已可以在出现后确定,后面的情况斗则可以不用考虑。

2021-10-22

  • 字符串日期天数问题,可以直接取一个基线例如1971年来计算天数。
  • 快速将map的key变成list的方式, 注意记忆.collect(Collectors.toList()):
1
List<Character> keyList = map.keySet().stream().collect(Collectors.toList())

2021-10-23

  • 树的层序遍历打印不一定要用bfs, dfs也行的,就不用存object[]了。

2021-10-24

  • 下次碰到复杂单词校验,如果正则忘记了,则直接上状态机,会简单很多。
  • 状态变化设置不要放在枚举的构造器里做,初始化可能会出现null,如果顺序不对的话。放static块中做
  • 注意Arrays.stream()不支持对char[]操作。
  • 当遇到答案是乘起来或者很多数字加起来的时候, 最好直接改成long做计算,避免溢出。

2021-10-29

  • 链表转换题中,注意如果left和right会变化,则你原本想递归的东西可能会变动, 因此要提前缓存
  • Math.ceil() 可以实现向上取整, floor向下取整
  • Math.log可以求 Math.log(a) /Math.log(b) 等同于loga(b)

2021-10-30

  • 教训: 深度搜索时, 主要先确定层级,如果有n个东西必须做某件事,那就拿这东西做层级,中间for循环搜不同情况即可, 东西搜完了就说明符合条件
  • 注意,涉及按时间在图上走的情况,是可以制造一个三维的图(数组),用时间做某一个维度即可避免冲突或者搞乱。

2021-11-21

  • 遇到边界问题很难受,不知道-1还是-0的,自己冷静下来模拟一下
  • 1-9有9个1位, 10-99的有90个2位, 100-999有900个*3位, 问你第1000位是1-∞中的哪个数字。
    这时候冷静处理闭上列出来 9个 180个 811个
    811个中,分别是 100 101 102 103
    让序号从0开始,则811-1 = 810, 然后用除法和取余即可。
  • 注意要用到取余判断某位是什么时,记得序号从0开始

2021-11-22

  • 洗牌算法: 数组0-n,每次对n随机取余后,将对应位置的数字交换到最后一位,然后减少n,继续操作。
  • rand.nextInt()的范围是负无穷到正无穷, 如果rand.nextInt()%M, 则范围为-M 到M。 因此应该改成rand.nextInt(M), 则范围为0-M-1

2021-11-24

  • stream中join的用法:.collect(Collectors.joining(“,”)), 而不是直接join
  • 环形数组如果要求避免头尾相碰, 可以选择去掉头或者去掉尾,做2次, 就能不考虑环的问题了
  • 动规、个数问题,优先考虑 dp[从i到末尾][某条件] 而非用区间去判断

2021-11-25

  • 树的左边界、叶子、右边界问题, 如果时间紧急,用3次遍历解决即可。 如果追求代码精致, 则用2个标记,不断往下传递,根据情况变化,需要自己考虑好边界条件,慎用。
    e0d7714912cb467741ce63ebb6430b7300a96e1e

2021-11-26

  • 如果要求在10000*10000的数字中进行多次不重复的随机选取, 内存不够的情况下, 可以利用map映射,将已被选的数字和末尾数组数字进行映射。
    4cb1e2e718d8888408ecc5093f3ba79375869d08

2021-11-28

  • 最大最小值问题,一定要注意如果最大最小是同一个值的情况
  • Math.abs(a-b)-1 误写成了 Math.abs(a-b-1), 绝对值计算一定要注意-1是不是写错位置了
  • 带条件的并查集(即满足条件才能相连), 应当按时间顺序做尝试性连接, 连完后发现不符合条件,则要重置该节点的parent,避免后面连错。
  • 并查集结果返回时,返回前的判断应该是 findParent(node) 是否满足而非parent[node]是否满足, 因为可能还没做压缩。

2021-11-29

  • 迭代法前序遍历树: 往栈里放儿子时,直接倒序放入即可。
  • 如果前面的信息可以利用,则考虑用滑动窗口,减少空间占用。(删掉一个元素以后全为 1 的最长子数组)
  • 原地矩阵置0问题, 考虑用第一行和第一列来做临时存储,然后用标记变量判断第一列和第一行是否需要置0。

2021-11-30

  • 数字不相邻排列问题,按数量从大到小插入,插入时先偶数位插入,再奇数位插入,则一定保证题目要求
  • 统计子串中的唯一字串。碰到某些问x唯一的情况, 想办法从x的角度出发找唯一的串或者子序列。
  • 想不到的时候,试着换一个维度去,原本是从a推b, 看下能否从b推a

2021-12-01

  • String自身按照字段序重新组合方法:
1
2
3
char[] cs = str.toCharArray();
Arrays.sort(cs);
String key = new StringBuilder().append(cs).toString();
  • bfs题,注意y\x\ny\ny不要写错,每次写完检查一下
    5f3365c64c94fd12501c5136b52bfca74ad582f6

2021-12-02

  • 求最长回文子串, 注意 i和前面某中心的对称节点j, 则j的回文长度信息是可以进行利用的。
  • 全排列不一定要用dfs去搜索。因为 第4位时,它的可能性就是前面3位的可能性总和再拼上第四位。因此一直记录当前result全集, 然后走到第x位时,让第x位和result全集拼接,再生成一个新的result集合
  • k的子变量不要用kk, 同理不要用ii作为i的自变量, 很容易写错, 应该是indexK之类的,做到第一位不同,否则很容易写错。

2021-12-04

  • 如果本来是可以利用哈希表,但要求原地算法的题目, 则可以考虑用数组本身作为哈希表
  • 数组迭代期间不要试图取更新数组值,因为更新的话迭代的nums是会变的,并不是不变的。
  • 涉及运算符的题目, 用switch+string的特性即可, 不用搞OP枚举,太容易错了
  • 二维场景加?:表达式很容易漏加括号
    e0f19882380cf45d20ff05564b14a013cde11b8e
  • 二维场景如果不想加边界判断, 可以用这种扩充边界思路, counts设置成 counts[m+2][n+2], 然后坐标从1,1开始即可。

2021-12-05

  • 简单题如果发现要很麻烦的dfs时,直接看下数据范围,确认能否从全集上去直接计算结果,而非从搜索去推导结果。
  • 求公共祖先或者树点到树点路径, 除了向上求祖先之类的外, 还可以用前缀法, 即求出根到2个点的路径,去除相同前缀即可。
  • 给一堆边,让你把他连成一条线(一笔画问题),且题目保证有借, 则考虑这是欧拉问题。 起点和终点是能明确的,直接用Hierholzer算法求。 具体见欧拉路径
  • 即需要边搜索边删除’边’的情况, 可考虑存储边的迭代器引用后,再进行搜索

2021-12-07

  • 括号的全排列问题, 可以用 (a)b的形式去利用a、b缓存逐步求解,不需要dfs
  • treeMap的floor 和celling总是记不清, floor——浮——水—— 要找的值在水上,但是只有下面的水key

2021-12-09

  • KMP算法的本质是[前缀-后缀]匹配算法, 后缀不匹配时,快速找到之前匹配部分的前缀位置。
  • 是否可按线性跳跃到某点的问题,如果发现从后往前不好判断,会超时,则试着从前往后,根据当前最远到达位置判断, 有点类似于bfs。
  • a+b>c时如果a+b可能溢出,则改成减法 a>b-c

2021-12-10

  • 不要做这种map.get()==map.get()的操作,高危操作。 Integer的==是引用。 要用equals。
  • 滑动窗口中的个数匹配问题,用下面这种if-else去判断是+1还是-1。
    69541d637f6c32d66f7415fe3ea1026572937dd6