当前位置: 首页 > news >正文

记录一下目前为止的算法成长

每日笔记

复习曲线

间隔1天、3天、7天、15天、30天,然后以一个月为周期复习

2023. 12. 24

一定要每天早中晚都要复习一下

早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义

11.29

开始向着面试刷题跟进!

每天刷4题左右 ,一周之内一定要是统一类型

而且一定稍作总结, 了解他们的内在思路究竟是怎样的!!

12.26

斐波那契数

爬楼梯

最小花费爬楼梯

不同路径1/2

12.28:

整数拆分

重点思路:一个正整数可以分为两个,或者多个,多个可以用dp[i-j]代替,一定不能直接分为乘以dp的情况,因为这就默认了必须拆分为三个以上

不同的二叉搜索树

重点思路: 把左右子树所有情况乘起来,递归子树的问题。注意左右节点个数的边界

12.29

01背包理论


12.30

分割等和子集

很难看出来是01背包。满足的条件有

  1. 每个元素只有取和不取两个状态
  2. 结果要满足,某一部分和,刚好等于什么什么value,而背包问题是在限制的重量内计算他们价值最大值, 这里只需把求最大值改成求刚好 == sum即可
  3. 此题的weight和value都是nums【i】,因为是一个一个数字要求刚好和为sum
  4. dp【i】代表在i内之和最大为多少 本题要求刚好等于sum所以结束条件是dp[ sum ] == sum ,即总量为sum之内刚好最大为sum!

最短无序连续子数组


12.31

209. 长度最小的子数组

思路:滑动窗口,先不断右移直到sum>=target , 然后左指针左移直到小于target,记录暂时的最小长度,然后继续右移右移直到sum>=target , 左指针左移直到小于target,不断迭代最小长度

和为 K 的子数组

使用前缀和,核心是

map.containskey(sum-k);
map.put(sum,map.getOrDefault(sum,0)+1);

152. 乘积最大子数组

重点思路:使用dp代表前i个最大乘积。但是我们注意到有可能含有负数,因此只记录max值是不行的,万一后面出现负数,乘上去大于max,就会使结果不对。

因此 我们需要两个dp数组,记录max和min,正和反向的最大值。每次迭代dp【i】时,我们需要比较【当前数字、上一个max乘以当前数字、上一个min乘以当前数字】,最大最小都记录下来。同时不断用max迭代结果res。

优化方式仍然可以采用迭代法。

4.打家劫社:这个屋子偷不偷,偷就加dp[i-2],不偷就等于dp【i-1】

有一个困扰很久的问题:

我以为这个递推公式的意思是相邻的两个元素必须有一个得取。

其实并不是,只是限制了要不要取 i ,没说不取 i 就要取 i-1 ,我们等于的是dp【i-1】!注意定义!所以有可能出现连着两个都不取。但是不可能出现连着三个都不取。

2024 . 1 . 1

无重复字符最长子串

记住map里存放的是当前元素及其下标。如果有就更新到i和最新的

1.15

结束了13天的期末 回归面试征途

算法:

最长子串老题

LRU缓存

知识点:

聚集索引和二级索引(非聚簇索引)

回表查询

什么是联合索引?

联合索引的创建

为什么需要注意联合索引中的顺序?

联合索引的优势

什么是索引失效

覆盖索引

索引创建的原则、什么时候创建

2.27

放完寒假归来第二天,正式进入状态,重新回归算法题和八股文密集时代

3.5号之前看完八股文,每天15集,算法题每天至少4道,开始!

无重复子串

2.28

LRU缓存

3.1

LRU缓存 18分钟ac

三数之和 的双指针解法,固定一个for循环再剩下两个双指针

反转链表复习了一遍迭代:为什么是now != null?因为迭代完now是最后一个的下一个,为什么是返回pre?因为pre是现在的最后一个,也就是反转过来以后链表的头部

还得复习递归法

3.3

数组中第k个最大元素

学会堆的相关知识,学会快速排序 和这道题解法

快速排序方法

通过设定第一个为基准值middle,还有左右两个边界,交替与middle比较,左比middle大就和右交换并且右开始扫描,左比middle小就继续扫描下一个(右比middle大就继续扫,比middle小就赋值给左并且左开始扫描)

超级重点!!!!必须先移动右指针再移动左指针 因为左指针一开始指的就是middle不能先移动

代码如下

 void quickSort(int[] nums,int low,int high) {if(low > high){return;}int left = low;int right = high;int middle = nums[low];while(low < high){while(low <  high && nums[high--] > middle);          nums[low] = nums[high];while(low < high && nums[low++] < middle);nums[high] = nums[low];}nums[low] = middle;//相遇点就是中值点quickSort(nums,left,low-1);quickSort(nums,low+1,right);}

堆排序方法

本题可以直接使用堆

把所有元素加入进去,当容量超过k时(要寻找的top k的数),就把heap顶的数poll出来,这样最终遍历完一定是top k的那些数字

class Solution {public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> heap = new PriorityQueue<>();for(int num:nums){heap.add(num);if(heap.size() > k){heap.poll();}}return heap.peek();}
}

堆的知识点

大顶堆:父节点大于左右儿子

小顶堆:父节点小于左右儿子

重点: 必须依次排满(从上到下从左到右按顺序排)

如何调整堆

LRU缓存

getNode里必须delete!!!因为要查看一本书,我们要抽出来放到顶层,也就是getNode = delete+putFront,抽出书getNode来处理

delete和putFront都是很单纯的功能!

注意put的写法,要putFront然后保存到map!

3.4

三数之和

本题需要积累的:

if(k>0 && nums[k]==nums[k-1] ) 必须是和k-1相比,不能是k+1,否则会漏掉多个k的结果
continue;

if(tmp < 0)

while(i < j && nums[i] == nums[++i]); 必须写成++i,这里既可以调整了i、j的位置,还可以去除重复的数, 一举两得

res.add(new ArrayList(Arrays.asList(nums[i],nums[j],nums[k]))); 记住这里的Arrays.asList()

反转链表

记住newHead就是底层的head,这个的逻辑就是先通过

注意一定是传入head.next而不是head,你传自己有什么意义?就成原地打转了 .next才是下一个

这一句进入最底层(这句的作用就是,递归的入口) 一层一层往回反转 每一层的head都自己做反转,返回newHead进入上一层

class Solution {public ListNode reverseList(ListNode head) {if(head == null || head.next == null){return head;}ListNode newHead = reverseList(head.next);head.next.next = head;head.next = null;return newHead;}
}

3.5

最小int的数是 Integer.MIN_VALUE

最大子数组和

明确:当前sum如果小于0了,则下一个数直接重置sum,重新开始累加,因为sum已经开始拖累了!

3.6

102. 二叉树的层序遍历

思路:把每一层node都放进队列里,遍历到了左右子节点就放进队列,依次遍历

以下为层序遍历基础代码:

void bfs(TreeNode root) {Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);while (!queue.isEmpty()) {TreeNode node = queue.poll(); // Java 的 pop 写作 poll()if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}
}

在本题中必须一层的在一个数组中,所以得用一个for循环控制每一层加入同一个Array中

92. 反转链表 II

思路

我们把链表分为左、中(反转区域)、右

找到要反转的区域的前一个节点和后一个节点,反转完区域内的节点以后再连接左右部分

用到一个dummy节点,这样防止特殊情况(left为1)

注意一开始循环体内代码,把left处连接到了begin,但是最后我们出来是修改了的 begin.next.next = now; 这句话就是在让left处的指针连接右部分,而begin.next = pre; 是在把左部分和right处连接上。这样左+翻转的中+右,得到了答案

3.7

最长回文子串

思路:

使用中心扩散法,for循环遍历数组中每一个元素,然后分别讨论一个为中心和两个为中心,传入fun函数去进行处理。

fun函数就是验证回文:以传入的参数作为中心,向两边扩散,记录长度和字符串,更新结果

注意点substring的用法:

substring不大写,且是用字符串实例s.substring来引用的

切割范围是左闭右开 [left,right) ,由于此处fun中我们设置的边界

因此退出循环时是在左边界左一位,所以left+1;但右边由于切割范围右开,所以right直接不变

3.10

合并两个有序链表

递归我们什么时候使用??也就是有重叠的子问题的时候

想清楚:

每一层子问题是什么

每一层函数返回的是什么含义

当前一层要干什么

递归的出口

本题就很典型,首先每一层返回的含义是剩下的已经接好的链表

本层要干的事情就是接当前的链表

我把后面搞定了的接上,然后这一层的我自己返回给上层,因为这层该我接上

23. 合并 K 个升序链表

最简单的困难题之一

思路:这种一直在动态的排序问题,就使用小顶堆,把所有链表头的节点加入进去,这样他会自动排序,我们每一次都可以拿出当前其中最小的那个,接在res队列后面

循环条件是heap不为空,如果空了就说明添加完了

每次拿出node以后接在后面,然后把node的下一个节点(非null)放进heap中。

注意点:

1.用堆要写全称PriorityQueue,小顶堆要附带((a,b)-> a-b)

2.heap的添加方法是offer()!!拿出方法是poll()!!

PriorityQueue<ListNode> heap = new PriorityQueue<>((a,b)->a.val - b.val);

25. K 个一组翻转链表

注意点:第三行!!!!!

还有循环条件k-1,因为一次是反转两个,两个两个的对换位置!

3.11

143. 重排链表

思路:

1.找到链表中点 分为左右部分

2.反转右半边部分链表

3.两个链表交替插入

23. 合并 K 个升序链表

最简单的困难题之一

思路:这种一直在动态的排序问题,就使用小顶堆,把所有链表头的节点加入进去,这样他会自动排序,我们每一次都可以拿出当前其中最小的那个,接在res队列后面

循环条件是heap不为空,如果空了就说明添加完了

每次拿出node以后接在后面,然后把node的下一个节点(非null)放进heap中。

注意点:

1.用堆要写全称PriorityQueue,小顶堆要附带((a,b)-> a-b)

2.heap的添加方法是offer()!!拿出方法是poll()!!

PriorityQueue<ListNode> heap = new PriorityQueue<>((a,b)->a.val - b.val);

3.12

33. 搜索旋转排序数组

重点是二分查找的各个边界

注意这个如果条件只是if(nums[mid] > nums[start]),那么当nums[mid]和nums[start]相等时,代码就不会进入这个分支,即使start和mid都指向升序部分的开始。这可能导致错过搜索目标值target的机会,特别是当target正好等于nums[start]或nums[mid]时。

这一堆条件要分清,跟mid不取等(等了不就是答案了),跟边界要取等!

主要是重点是先分清是在有序区域还是无序区域。我们只讨论有序区域的东西!

142. 环形链表 II

找循环位置,先找到相遇点,然后让p从head开始走slow从相遇点走,走到他们相遇就是答案点

注意此处必须这样写循环体。因为用其他写法会超时

也就是必须把(fast == slow)这个判断条件放在里面

148. 排序链表

核心思路:归并排序

先找中点拆分为左右两半,然后使用递归不断拆分成左右两半,每次返回上一层时都把下一层的排序好再返回上去

分析一下这里的递归:

子问题是:将左右两边的链表排序,返回排序以后的链表

递归函数的作用是进左右两层,本层的作用是合并两个链表并返回

注意

寻找中点时fast要从head下一个开始,因为我们要让slow指向right部分的前一个节点,获得right并且断开left和right!

class Solution {public ListNode sortList(ListNode head) {if (head == null || head.next == null)return head;ListNode fast,slow;slow = head;fast = head.next;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;}ListNode newhead = slow.next;slow.next = null;ListNode left = sortList(head);ListNode right = sortList(newhead);ListNode dummy = new ListNode(0);ListNode p = dummy;while (true) {if(left == null){p.next = right;break;}if(right == null){p.next = left;break;}if(left.val < right.val){p.next = left;left = left.next;}else{p.next = right;right = right.next;}p = p.next;}return dummy.next;}
}

2. 两数相加

独立做出来的mid!!!!!

直接朴朴素素的相加,使用tmp变量记录每两个节点的和,本层now就直接取余,下一层的用now取整

p1或者p2其中一个为null就不加,要不就加上,规避了长短不一的结果

退出 条件不仅要同时为null,还要保证tmp已经结算完毕了,防止最高位进一的情况

滑动窗口

按照这题为模板

这种题的特征是 "子串" "子数组" 这种需要连续元素的

有一个窗口在扫描,使用两个变量left限制左范围:right用于for遍历计数

tmp,max用于记录最终数据

从0处开始滑动区间 ,right每加一次,就判断right这个元素和窗口内的元素是否满足某种条件

如果不满足了就进入处理块, 不断把left向右推进直到他满足条件, 在外层循环记录tmp和最大的max即可.(此题判断的条件是是否有重复元素,有就把left推进到重复的位置)

无重复字符最长子串

字节最经典的一道题

/

注意要用HashMap提高查找效率

  1. containsKey先于put处理防止自己contains自己。调整i位置,通过比较两个元素下标谁大,来确定谁是后面的0
  2. 左边界调整位置的时候调整到第一个有效位(即重复位+1),而不是重复位,因为如果这个字符串没有重复的,此时应该使用j-i+1计算结果, 然而如果是调整到重复位 结果就变成了j-i,没有统一。所以必须挪到重复位的右边(第一个有效位)
  3. i = Math.max(i,map.get(s.charAt(j))+1); 这一句是比较 当前边界和重复字符谁更右 ,取更右边的作为边界重点:要用HashMap来搞。注意put是会覆盖相同的元素的!!!!由于遍历的顺序是下标由小到大,因此得到的那个重复元素的下标一定是目前最大的,直接和左边界比较即可

哈希表(12.9-12.16)

什么时候使用哈希法:

1.当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。

经典题: 比较两个集合的元素重叠的地方, 或者这个数组能不能由那个数组里的元素构成

2.当我们需要在一次遍历中记录某种元素出现的次数, 或者记录某个和他相关的特征的时候

抽象来说就是, 需要建立一个数据和另一个数据之间的映射关系的时候

下面是这两种数据结构的一些常用方法:

HashMap

  1. put(key, value): 如果key已经存在,那么值就更新
  2. get(key): 根据key获取value
  3. remove(key): 删除HashMap中指定key的元素
  4. containsKey(key): 检查HashMap中是否包含给定的key
  5. containsValue(value): 检查HashMap中是否包含给定的value
  6. keySet(): 返回所有key的Set
  7. values(): 返回所有value的Collection
  8. isEmpty(): 检查是否为空
  9. clear(): 清除所有元素
  10. map.put(i , getOrDefault(map.get(i),0)+1)

HashSet

  1. add(element): 添加一个元素
  2. remove(element): 删除一个元素
  3. contains(element):是否包含给定的元素
  4. isEmpty(): 检查是否为空
  5. clear(): 清除所有元素
  6. size(): 返回元素的数量
  7. iterator(): 返回一个迭代器,用于遍历HashSet中的所有元素。

回溯(12.19-12.24)

为什么要用回溯?

  • for循环只能有单层遍历,但是回溯是可以多层遍历
  • 回溯的本质就是多层遍历, 用for循环控制这一层的广度, 用递归控制深度, 用退出条件控制结束时机
  • 一定要画图辅助理解,可以明确写递归方法的思路, 这很重要
  • 什么题用回溯?问你返回所有可能得什么什么组合,集合, 需要枚举/遍历所有情况 , 特别是组合/子集问题,要从题目抽象中出来

基本步骤

  1. 定义结果res集合(ArrayList) 临时存储tmp集合(LinkedList) 当前总和int sum
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new LinkedList<>();
int sum=0;
  1. 定义dfs函数, 包含传入的数组nums, 每次遍历的开头begin, 目标target
  2. 定义退出条件: 等于target时 把tmp加入res然后返回 超出target直接返回 大小超出也返回
  3. 定义循环体:注意for(i=begin;i<length;i++)
tmp.add(candidates[i]);
sum += candidates[i];
dfs(candidates, i ,target);
sum -= candidates[i];
tmp.removeLast();

三大要点总结

  • 数组中(有无)重复元素
  • 结果中(能否)含有重复元素
  • 结果(能否)出现重复集合(顺序不同是否算同一个集合)

主要是修改i = begin参数 和 dfs(nums, i ,target)中是 i 还是 i+1

子集能重复, 只用修改为 i=0 不可重复则是 i=begin

重点情况:

  1. 数组中无重复元素 结果中不能含有重复元素 子集不能出现重复: i=begin dfs(nums, i+1 ,target)
  2. 数组中有重复元素 结果中能含有重复元素 子集不能出现重复: 加条件:if(i > begin && nums[i] == nums[i-1]) continue;i=begin dfs(nums, i+1 ,target)
  3. 数组中有重复元素 结果中不含有重复元素 子集不能出现重复:加条件:if(i > 0 && nums[i] == nums[i-1]) continue;i=begin dfs(nums, i+1 ,target)###

回文子串问题

12.28

class Solution {List<List<String>> res = new ArrayList<>();List<String> tmp = new LinkedList<>();public List<List<String>> partition(String s) {int index = 0;dfs(0,s);return res;}public void dfs(int index , String s){if(index == s.length()){res.add(new ArrayList(tmp));}for(int i = index;i < s.length();i++){if(fun(index,i,s) == true) {String now = s.substring(index,i+1);tmp.add(now);dfs(i+1,s);tmp.removeLast();}}}public boolean fun(int i,int j,String s){while(true){if(i >= j)return true;if(s.charAt(i) != s.charAt(j)){return false;}i++;j--;}}}

. - 力扣(LeetCode)

可以算困难一级的了

难点:

  • 把分割方案化为回溯问题, 我们想枚举每一种字符串的分割方式, 再一个一个去验证
  • 可以看做是字符间空隙的组合问题(在一个空隙集合中选择不同的空隙组合) 采用回溯枚举
  • 因为for循环只能有单层遍历,但是回溯是可以多层遍历(回溯的本质就是遍历, 用for循环控制这一层的广度, 用递归控制深度, 用退出条件控制结束时机 )
  • 一定要画图辅助理解, 这很重要,一开始都没意识到
  • 判断回文直接双指针
//我们使用index来代表当前遍历的空隙, 当枚举到**最后一个字符后**的空隙时就才遍历
if(index == s.length())  
{res.add(new ArrayList(tmp));
}for(int i = index;i < s.length();i++)
{//index和i表示我们当前处理的哪两个空隙之间的字符串,只有当前满足是回文我们才继续去dfs,否则直接进入下一个循环,这样保证了只有回文, 并且因为只有遍历到最后一个字符后才会结束,所以不用担心会脏结果if(fun(index,i,s) == true) {String now = s.substring(index,i+1);  //注意边界是[index,i]tmp.add(now);dfs(i+1,s);//从下一个字符开始继续判断tmp.removeLast();}
}

动态规划(12.25-1.4)

如果某一问题有很多重叠子问题,使用动态规划是最有效的。

就是你发现这一步的答案要根据上一步的答案得,而且上一步的答案也是同样的方法得到的

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的

状态转移公式(递推公式)是很重要,但动规不仅仅只有递推公式。


动规五步曲(一定要明确的每一步结果写出来)

  1. 确定dp数组(dp table)以及下标的含义这很重要,注释出来
  2. 确定递推公式写完dp数组含义以后 立马着手递推公式 用注释先写上
  3. dp数组如何初始化一定要注意dp[0] dp[1] 这种边界值的初始化,很有可能要取特值
  4. 确定遍历顺序要确保后面的可以由前面的推出来,特别是多维dp
  5. 举例推导dp数组


为什么要先确定递推公式,然后在考虑初始化呢?因为一些情况是递推公式决定了dp数组要如何初始化!

Debug三问

  1. 这道题目我举例推导状态转移公式了么?
  2. 我打印dp数组的日志了么?
  3. 打印出来了dp数组和我想的一样么?

背包问题

01背包

(1)

对于背包问题,有一种写法即dpi 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

确定递推公式

不放物品i:和上一个相同。由dp[i - 1] [j]推出,即背包容量为j,里面不放物品i的最大价值,此时dpi就是dp[i - 1] [j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。)

放物品i:等于上一个加这个的value。由dp[i - 1] [j - weight[i]]推出,dp[i - 1] [j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1] [j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值

取i那就是后者,不取i就是前者

dp[i][j] = max{ dp[i-1][j] , dp[i-1][j-weight[i]] + value[i] }

(2)滚动数组法

重点一定要记住, 就是数据的覆盖

在此时,数组是一遍一遍覆盖的。覆盖前就相当于原来的dp[i-1 ] [j ],所以此时,不取物品i 的情况就可以化为dp[j ] 直接就是上一个的。同理,要取物品i 就直接化为dp[j-weight ]+value[j ]

dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]

初始化dp就应该全是0,在题目给的全是正整数的情况下可以保证后续被覆盖掉

循环还是双重循环,要有i 控制前n个物品进不进去, 但是dp会减少一维度

同时我们可以窥见遍历的次序问题。因为我们要保证j 之前的数据还没有被覆盖

因为有比较dp[j - weight[i]] + value[i]的部分

所以我们要倒序遍历

ps:能不能交换遍历顺序?不能,不然就变成 dp[j]表示:取前 j 个的背包,所背的物品价值可以最大为dp[j]

链表

反转链表

迭代法:为什么是now != null?因为迭代完now是最后一个的下一个,为什么是返回pre?因为pre是现在的最后一个,也就是反转过来以后链表的头部

递归法:记住newHead就是底层的head,这个的逻辑就是先通过

注意一定是传入head.next而不是head,你传自己有什么意义?就成原地打转了 .next才是下一个

这一句进入最底层(这句的作用就是,递归的入口) 一层一层往回反转 每一层的head都自己做反转,返回newHead进入上一层

class Solution {public ListNode reverseList(ListNode head) {if(head == null || head.next == null){return head;}ListNode newHead = reverseList(head.next);head.next.next = head;head.next = null;return newHead;}
}

反转链表2

最优解,先找出pre,然后直接穿针引线再拉直,代码量极少,模仿反转k链表

注意

第三行是pre.next

注意

每次是将两个节点一起反转所以是b-a

环形链表

重点:

快指针要在head。next不然你slow永远等于fast

必须先判断fast,因为后面的有可能报空指针异常

重排链表

思路:

1.找到链表中点 分为左右部分

2.反转右半边部分链表

3.两个链表交替插入

合并两个有序链表

递归我们什么时候使用??也就是有重叠的子问题的时候

想清楚:

每一层子问题是什么

每一层函数返回的是什么含义

当前一层要干什么

递归的出口

本题就很典型,首先每一层返回的含义是剩下的已经接好的链表

本层要干的事情就是接当前的链表

我把后面搞定了的接上,然后这一层的我自己返回给上层,因为这层该我接上

K 个一组翻转链表

先算出长度,再使用两个循环去处理!

注意点:第三行!!!!!因为我们采用的是:把开头节点右侧的节点一个接一个挪到pre.next头插法

因此是把nex接到pre.next

还有循环条件k-1,因为一次是反转两个,两个两个的对换位置!必须K-1

合并 K 个升序链表

最简单的困难题之一

思路:这种一直在动态的排序问题,就使用小顶堆,把所有链表头的节点加入进去,这样他会自动排序,我们每一次都可以拿出当前其中最小的那个,接在res队列后面

循环条件是heap不为空,如果空了就说明添加完了

每次拿出node以后接在后面,然后把node的下一个节点(非null)放进heap中。

注意点:

1.用堆要写全称PriorityQueue,大顶堆要附带((a,b)-> a-b)

2.heap的添加方法是offer()!!拿出方法是poll()!!

PriorityQueue<ListNode> heap = new PriorityQueue<>((a,b)->a.val - b.val);

328. 奇偶链表

把一个链表的奇数和偶数节点分别合在一起,再相连

直接创建两个节点作为奇偶链表的开头,容纳完再接上即可

二叉树


代码

236. 二叉树的最近公共祖先

103. 二叉树的锯齿形层序遍历

记住有三个数据结构

一个当容纳节点的队列,一个是res,一个是tmp,不要把tmp和Deque搞错了

这个题直接在层序遍历基础上

在添加tmp的时候正向添加反向添加就好了,一组一组的呀他是

你在那儿管deque的添加顺序不是纯纯给自己找麻烦吗

110. 平衡二叉树

相关文章:

记录一下目前为止的算法成长

每日笔记 复习曲线 间隔1天、3天、7天、15天、30天&#xff0c;然后以一个月为周期复习 2023. 12. 24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 11.29 开始向着面试刷题跟进! 每天刷4题左右 ,一周之内一定要是统一类…...

AI大模型学习在数控系统工艺优化与智能制造中的应用

目录 1.工艺优化&#xff1a; 2.预测维护&#xff1a; 3.质量控制&#xff1a; 4.自动编程&#xff1a; 5.人机协作&#xff1a; 6.系统集成&#xff1a; AI大模型学习在数控系统工艺优化与智能制造中的应用主要体现在以下几个方面&#xff1a; 1.工艺优化&#xff1a; …...

安卓findViewById 的优化方案:ViewBinding与ButterKnife(一)

好多小伙伴现在还用findViewById来获取控件的id, 在这里提供俩种替代方案&#xff1a;ViewBinding与ButterKnife&#xff1b; 先来说说ButterKnife ButterKnife ButterKnife是一个专注于Android系统的View注入框架&#xff0c;在过去的项目中总是需要很多的findViewById来查…...

map和set(三)——红黑树

1、红黑树的概念及性质 1.1概念 概念&#xff1a; 红黑树是一种二叉搜索树&#xff0c;以颜色(Red or Black)互斥来限制每条路径不会比另外的路径长出两倍&#xff0c;来达到近似平衡 1.2性质 红黑树的性质&#xff1a; 每个节点不是黑色就是红色根节点是黑色的如果一个节点是…...

Day26 HashMap

Day26 HashMap 文章目录 Day26 HashMap一、应用场景二、特点三、基本用法四、面试题 一、应用场景 1、概念&#xff1a; HashMap是Java集合框架中的一种实现类&#xff0c;用于存储键值对。 2、好处&#xff1a; HashMap是一个常用的集合类&#xff0c;适用于需要快速查找和插…...

某蓝队面试经验

背景 据小道消息说今年的国护疑似提前到了五月份&#xff0c;所以最近也是HW面试的一个高峰期啊&#xff0c;这里分享一下上次长亭的蓝队面试问题&#xff08;附本人的回答&#xff0c;仅供参考&#xff09; 面试问答 1、谈谈作为蓝队护网过程使用过厂商的设备 这里我回答的…...

【Linux】 centos7安装卸载SQL server(2017、2019)

一、安装配置 准备一个基础Linux配置&#xff1a; 内存为20GB 运行内存为2GB的系统&#xff08;数据库小于2GB安装不了&#xff09; 1、网络配置 我们需要进行网络的连接 进入 cd /ect/sysconfig/network-script/ 编辑文件ifcfg-ens33 vi ifcfg-ens33 Insert键进行编辑 把ONBOO…...

面试算法-110-课程表

题目 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学习课程 ai 则 必须 先学习课程 bi 。 …...

注册前后端php的检测

首先&#xff0c;在HTML表单中添加一个用于输入密码的文本框&#xff0c;并在其后面添加一个用于显示密码格式要求提示的元素&#xff0c;例如一个 <span> 标签。 <input type"password" id"passwordInput"> <span id"passwordHint…...

Redis:什么是redis?①

一、思想 Redis是一个开源的高性能基于内存key-value数据库&#xff0c;常用作数据库、缓存或消息代理 二、数据类型 String List...

【课程】MyBatisPlus视频教程

MyBatis-Plus是一款非常强大的MyBatis增强工具包,只做增强不做改变. 在不用编写任何SQL语句的情况下即可以极其方便的实现单一、批量、分页等操作。 本套教程基于MyBatis-Plus新2.3版本,详细讲授&#xff1a;集成Mybatis-Plus、 通用CRUD、EntityWrapper条件构造器、ActiveRec…...

如何使用人工智能和ChatGPT来优化营销转化率

人工智能 &#xff08;AI&#xff09; 和营销的交集正在彻底改变企业与客户互动的方式&#xff0c;最终改变营销转化率。人工智能能够分析大量数据、理解模式和自动执行任务&#xff0c;它不仅是一项创新技术&#xff0c;而且是营销领域的根本性转变。这种转变允许更加个性化、…...

Ubuntu 22.04上构建libvirt源码错误解决

当在Ubuntu 22.04上构建libvirt源码时&#xff0c;可能会遇到一些错误。下面是一些常见错误及其解决方法&#xff1a; 1. 错误&#xff1a;Program xmllint’未找到或不可执行 解决方法&#xff1a;安装libxml2-utils sudo apt-get install libxml2-utils2. 错误&#xff1a…...

游戏客户端面经

1&#xff0c;3D的模型怎么显示到2DUI上面 2&#xff0c;C#的ArryList和List的区别 3&#xff0c;接口和抽象类的区别&#xff0c;一般什么时候用接口 4&#xff0c;UGUI怎么渲染的UI&#xff0c;UGUI的层级管理&#xff08;怎么不打断合批&#xff09;&#xff0c;合批流程…...

AS,idea,maven,gradle

Jdk,sdk。提前都是需要下好的。 Maven与gradle的思考&#xff1a; 用AS开发app时&#xff0c;gradle本就有&#xff0c;自己也可以指定&#xff0c;AGP同样。要注意gradle&#xff0c;AGP,jdk版本的事情。还有依赖库。 用idea开发网络程序时&#xff0c;也有内置的maven&…...

ElasTool v3.0 程序:材料弹性和机械性能的高效计算和可视化工具包

分享一个材料弹性和机械性能的高效计算和可视化工具包&#xff1a; ElasTool v3.0。 感谢论文的原作者&#xff01; 主要内容 “弹性和机械性能的高效计算和可视化对于材料的选择和新材料的设计至关重要。该工具包标志着材料弹性和机械性能计算分析和可视化方面的重大进步…...

Redis入门级详解(一)

一、Redis入门介绍 1、什么是Redis? Redis&#xff0c;英文全称是Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。…...

java算法题每日多道六

138. 随机链表的复制 题目 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对…...

C# 特性(Attribute)

C# 特性&#xff08;Attribute&#xff09; 文章目录 C# 特性&#xff08;Attribute&#xff09;Obsolete语法示例代码 创建自定义特性&#xff08;Attribute&#xff09; Obsolete 这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例…...

Redis 教程系列之Redis 配置(三)

Redis 配置 Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf(Windows 名为 redis.windows.conf)。 你可以通过 CONFIG 命令查看或设置配置项。 语法 Redis CONFIG 命令格式如下: redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME 实例 redis 127.0…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql

安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了&#xff0c;系统很多命…...

基于小程序老人监护管理系统源码数据库文档

摘 要 近年来&#xff0c;随着我国人口老龄化问题日益严重&#xff0c;独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长&#xff0c;随之而来的是日益突出的老年人问题&#xff0c;尤其是老年人的健康问题&#xff0c;尤其是老年人产生健康问题后&…...

自定义线程池1.2

自定义线程池 1.2 1. 简介 上次我们实现了 1.1 版本&#xff0c;将线程池中的线程数量交给使用者决定&#xff0c;并且将线程的创建延迟到任务提交的时候&#xff0c;在本文中我们将对这个版本进行如下的优化&#xff1a; 在新建线程时交给线程一个任务。让线程在某种情况下…...

Qt/C++学习系列之列表使用记录

Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件&#xff0c;同步使用QTableWidgetItem进行单元格的设置&#xff0c;最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…...