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

news2024/12/23 17:26:40

每日笔记

复习曲线

间隔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. 平衡二叉树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1532466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这里是一本关于 DevOps 企业级 CI/CD 实战的书籍...

文章目录 &#x1f4cb; 前言&#x1f3af; 什么是 DevOps&#x1f3af; 什么是 CI/CD&#x1f3af;什么是 Jenkins&#x1f9e9; Jenkins 简单案例 &#x1f3af; DevOps 企业级实战书籍推荐&#x1f525; 参与方式 &#x1f4cb; 前言 企业级 CI/CD 实战是一个涉及到软件开发…

AIOCR:AI文字识别web集成系统@Kylin+RISCV

基于kotti_ai的AI文字识别web集成系统 AIOCR项目目标&#xff1a; 在KylinRISCV搭建一个kotti_ai构架的网站&#xff0c;提供AI OCR文字识别web服务。 二期目标&#xff1a;在AIOCR的基础上提供chatgpt和文心一言等大模型调用&#xff0c;建立综合大模型应用平台。 功能&am…

STL_list文档使用介绍与底层代码实现简介

文章目录 list介绍list的使用构造函数&#xff08;constructor&#xff09;迭代器list capacitylist modify&#xff08;修改&#xff09;其他接口函数list迭代器失效问题 list实现基础框架(节点类&#xff09;基础框架&#xff08;迭代器类&#xff09;基础框架&#xff08;链…

爬虫系列-CSS基础语法

&#x1f308;个人主页&#xff1a;会编程的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” CSS全称层叠样式表 &#xff0c;主要用来定义页面内容展示效果的一门语言&#xff0c;HTML&#xff1a;页面骨架&#xff0c;素颜CSS&#xff1a;页面效果美化&#xff1a…

【概念】神马是分布式?

SueWakeup​​​​​ 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习Java框架 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f7; 友情赞助播出&#xff01; 目录 前言 1. 系统架构的演变 2. SOA 与微服务的关系 3. 分布式核心知识…

PCL QT visualizer

PCL QT visualizer 用Qt创建PCL 可视化应用程序。 项目组织 UI界面 Compile & Run cmake -B build -S . -DCMAKE_TOOLCHAIN_FILED:\vcpkg\scripts\buildsystems\vcpkg.cmakecmake --build build --config Releasewindeployqt6.exe .\pcl_visualizer.exe.\build\Release\…

“因聚而生,数智有为”实在智能Agent牵手华为生态合作

近日&#xff0c;2024华为中国合作伙伴大会顺利闭幕&#xff0c;实在智能受邀出席&#xff0c;携TARS大模型及实在Agent&#xff08;智能体&#xff09;数字员工精彩亮相&#xff0c;与华为生态伙伴共同探讨如何帮助客户抓住数智化转型的巨大机遇&#xff0c;加速培育“新质生产…

Python数学建模-2.9Matplotlib库

Matplotlib库是Python中一个非常流行的绘图库&#xff0c;它提供了大量的绘图工具&#xff0c;可以生成各种类型的静态、动态、交互式的图表。Matplotlib的设计初衷是为了与NumPy配合使用&#xff0c;从而提供一个强大的数学绘图工具。 1.Matplotlib的主要特点 丰富的图表类型…

vue2 中使用音频

vue2 中使用音频 在 template 页面 写入 audio 标签 <template><div><audio ref"moreAudio" :src"moreAudioSrc"></audio><audio ref"noAudio" :src"noAudioSrc"></audio></div> </t…

MySQL 索引的分类和优化

​ 优质博文&#xff1a;IT-BLOG-CN 索引是什么 &#xff1a; MySQL 官方对索引的定义&#xff1a;索引&#xff08;Index&#xff09;是帮助 MySQL 高效获取数据的数据结构。可以得到索引的本质&#xff1a;索引是数据结构。索引的目的在于提高查询效率。可以简单理解为&#…

css实现的3D立体视觉效果鸡蛋动画特效

这是一个基于纯css实现的3D立体视觉效果鸡蛋动画特效&#xff0c;喜欢的朋友可以拿来使用演示动态效果 css实现的3D立体视觉效果鸡蛋动画特效

音频和视频标签

音频用audio标签 controls表示控制栏 loop循环播放音频 autoplay自动播放&#xff08;浏览器基于隐私一般不支持&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Com…

从零到一构建短链接系统(八)

1.git上传远程仓库&#xff08;现在才想起来&#xff09; git init git add . git commit -m "first commit" git remote add origin OLiyscxm/shortlink git push -u origin "master" 2.开发全局异常拦截器之后就可以简化UserController 拦截器可以…

分布式文件存储与数据缓存(二)| Redis

目录 Redis概述_什么是NoSQLNoSQL的四大分类KV型NoSql&#xff08;代表----Redis&#xff09;列式NoSql&#xff08;代表----HBase&#xff09;文档型NoSql&#xff08;代表----MongoDB&#xff09;搜索型NoSql&#xff08;代表----ElasticSearch&#xff09; 关系型数据库和非…

【Kotlin】扩展属性、扩展函数

1 类的扩展 Kotlin 提供了扩展类或接口的操作&#xff0c;而无需通过类继承或使用装饰器等设计模式&#xff0c;来为某个类添加一些额外的属性或函数&#xff0c;我们只需要通过一个被称为扩展的特殊声明来完成。通过这种机制&#xff0c;我们可以将那些第三方类不具备的功能强…

Css提高——Css3盒子模型border-box

1、盒子模型的种类与区别 CSS3 中可以通过 box-sizing 来指定盒模型&#xff0c;有2个值&#xff1a;即可指定为 content-box、border-box&#xff0c;这样我们 计算盒子大小的方式就发生了改变。 CSS3 盒子模型 可以分成两种情况&#xff1a; 1. box-sizing: content-box 盒…

智慧安全:守护智慧城市的安全屏障

随着信息技术的迅猛发展&#xff0c;智慧城市已成为现代城市发展的重要方向。智慧城市通过集成应用先进的信息通信技术&#xff0c;实现城市管理、服务、运行的智能化&#xff0c;为城市的可持续发展注入了新的活力。然而&#xff0c;在智慧城市的建设过程中&#xff0c;安全问…

华为openEuler系统卸载jdk

华为openEuler系统卸载jdk 1.查看openEuler上已安装的 Java 版本&#xff1a; 在终端中运行以下命令&#xff0c;查看系统中已经安装的 Java 版本。 sudo alternatives --config java这将列出已安装的 Java 版本&#xff0c;你可以看到当前使用的是哪个版本 2.卸载 Java&am…

SpringCloudAlibaba Nacos配置及应用

Nacos搭建及配置 nacos本机服务搭建 windows上搭建单机nacos&#xff1a; Releases alibaba/nacos GitHub 下载安装包 下载本地&#xff0c;解压&#xff0c;直接运行&#xff08;保证安装包的绝度路径只有英文字符&#xff0c;有中文会导致运行失败&#xff09;&#xff…

测试平台——前端框架

一、创建vue项目 npm init vitelatest web_class wylWYLdeMacBook-Air testplatform % npm init vitelatest web_class ✔ Select a framework: › Vue ✔ Select a variant: › JavaScriptScaffolding project in /Users/wyl/workspace/testplatform/web_class...Done. Now…