lc刷题记录

置顶

arrays和collectios工具类的常见方法
asList需要有返回值

Arrays.copyOfRange()数组中截取一部分

toArray

List 转换成 int[]的两种方式
stream API
return res.stream().mapToInt(Integer::intValue).toArray();

res.stream():将 List 转为 Stream
.mapToInt(Integer::intValue):将 Stream 转为 IntStream(基本类型流)。
.toArray():将 IntStream 转为 int[]

toArray
res.toArray() 返回的是 Object[] 数组
toArray(T[] a) 只能用于对象类型数组(如 Integer[]),不能用于基本类型数组(如 int[])。

如果尝试 res.toArray(new int[0]),编译器会报错,因为 int[] 不是 Object[] 的子类

栈与队列

用栈实现队列 用队列实现栈

队头出,队尾插入
peek是获得队头元素 poll出队列 add入队列

Queue<Integer> q = new LinkedList<>();
Deque<Integer> deque = new LinkedList();
Deque与Qeque都是接口,LinkedList是实现类,面向接口编程的思想(还不太理解)

3.26
在Java中,你可以使用接口类型定义变量或引用,只需在赋值时给它一个实现了这个接口的类实例即可。
上面那种面向接口的编程只需要在修改代码时候修改一下实现类的名称,很方便,大多数代码都不用修改

Map<String, Integer> map = new HashMap<>();
map.put("苹果", 5);

// 这里entry就是Map.Entry接口的引用,实际存放的是HashMap内部的Node对象。
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " = " + entry.getValue());
}


LinkedList实现了多个接口:

  • LinkedList 实现了 Queue 接口,可作为队列使用。
  • LinkedList 实现了 List 接口,可进行列表的相关操作。
  • LinkedList 实现了 Deque 接口,可作为队列使用。
  • LinkedList 实现了 Cloneable 接口,可实现克隆。

150逆波兰表达式

栈的方式,比较简单
注意代码要简洁,直接return,不要去申明一些没必要的变量

416分割相同子集

dp背包问题推导(由二维向一维),注意有个if判断
增强for别写错了
注意内层的for循环逆序
能否装满问题

494目标和

最开始的思路是一个0-sum的大二维数组,没法转换为1维的且没有考虑负数的情况;
题解的加法袋和减法袋感觉很巧妙,转换为一维的,问题是怎么将普通问题联想到滚动背包问题呢
注意初始化
用一维dp需要逆序
装法问题

474.一和零

状态转移较好写
str.toCharArray()

518.零钱兑换

dp[j]+=dp[j-nums[i]]

377.组合总数

求装法 vs 求价值
求的是排列,先遍历背包容量,再遍历物品

322.零钱兑换

完全背包 没有排列的概念
求需要的最少数量
代码可能会尝试用 max + 1 来更新 dp[j],这会导致整数溢出

279.完全平方数

全背包,排序问题先遍历背包??
其实感觉这道题跟背包关系不大,一般思路也能做出来
时间复杂度n^3

213.打家劫舍

基础打家劫舍较简单,环形打家劫舍没写出来
考虑两种情况,有首无尾,有尾无首,同时注意代码涉及到整块复用就考虑写下函数(虽然只复用了两次
在写singlerob函数的时候,注意初始化的dp是什么样的,尽量与nums每个i的位置保持一致
最后更简单的方法就是,反正是数组连续三位之间的关系,直接三个变量也能实现dp的效果

300.最长递增子序列

Arrays.fill(array, 100) 数组填充
应该算是二维dp,第一次写的时候只想到了一维,想着当前数字与前一个数字进行比较
实现的时候还有一个点,求最长子序列,可能不包括最后一个元素,和普通dp不一样
dp的含义是以nums[i]结尾的最长递增子序列;

674.最长连续递增序列

dp的含义是以nums[i]结尾的最长连续递增序列

中间好多次没写

编辑距离类问题

115.不同的子序列

583.两个字符串的删除

72.编辑距离

写出递推公式之后就比较简单
注意初始化,115只需要初始化第一行,第一列不需要,583和72需要初始化第一行与第一列,结合dp含义来看,初始化的长度也是n+1(与声明的dp数组长度保持一致)

647.回文子串

关键是得找到合适的递推关系,dp的定义也要合适
迷糊迷糊

回溯

子集问题分析

时间复杂度: 因为每一个元素的状态无外乎取与不取,一共2n种状态,每种状态都需要n的构造时间,最终时间复杂度为n*2n
空间复杂度: 递归深度为n,所以系统栈所用空间为n

216.组合总和3

剪枝:如果选完这个数字,总和大于目标sum,直接剪枝;还有个如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了

39.组合总数

获得的是排列??啊啊啊小失误,传到backtracing方法中的idx应该是i而不是一次遍历中固定不变的begin

40.组合总数2

上一题无重复元素,这一题有重复元素,但是结果仍然不能有重复的组合
used标记数组,
candidates[i] == candidates[i - 1] false说明结束了一次循环,说明是同树层重复;true说明上层用了candidates[i],说明是同树枝重复

17.电话号码

思路较简单,但实现起来并不容易,一些字符串的操作不太了解,stringbuilder,charAt,还有就是具体的步骤,这个横向for遍历应该先把数字对应的字符串拿出来

一些小方法

list取最后一个元素list.get(list.size()-1),hashset相关操作
string的charAt方法,stringbuilder相关append,deleteCharAt……

子集和全排列

都比较简单

131.分割回文串

竟然一下就通了呜呜
substring左开右闭,注意for遍历应该是小于等于s.length

491.递增子序列

注意由于无法进行sort,因此去重不能用used标记数组,用hashset

贪心

看了几个例子,dijkstra算法和找最小生成树的两个算法
最小生成树(无环,所有边的权值加一起最小)

53.最大子数组和

dp做过,贪心更简单
注意要记录最大子序列和,sum只是累加子序列和,走到最后不一定是最大的,类似于result的用法

分发糖果

正向反向遍历,每个位置取max值
在流的每个操作中会涉及到 函数调用 和 lambda 表达式 的解析。对比直接使用传统的 for 循环,流处理需要额外的 方法调用开销

柠檬水找零

简单

k次取反最大数组和

加油站

感觉较难,好难理解

452.用最少数量的箭

还是活动分配时间段问题,求最多可以安排的活动数,但是不一样的是,端点重复也算重复,判断条件注意不包括等于

comparator比较器的用法,直接return o1-o2,对于一些刁钻的测试用例小心整型溢出
可以使用Integer.compare(底层是比较逻辑,不是直接相减),或者改写compare的逻辑

int与Integer
https://blog.csdn.net/chenliguan/article/details/53888018
int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换
java对于Integer与int的自动装箱与拆箱的设计,是一种模式:叫享元模式(flyweight)。
(1)加大对简单数字的重利用,Java定义在自动装箱时对于在-128~127之内的数值,它们被装箱为Integer对象后,会存在内存中被重用,始终只存在一个对象。
(2)而如果在-128~127之外的数,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象。
Java 规定了一个 Integer 缓存池(cache),默认缓存范围是 -128 到 127,要么返回缓存中的对象,要么返回堆中新建的对象

435.无重叠区间

还是活动分配时间段问题,求的是总活动数-最多可以安排的活动数

56.合并区间

与活动分配问题类似,但是这次求得是最长覆盖时间,对区间左端点进行排序

找到合适的数据结构来存储数据,同时注意写法 List<int[]>

406.根据身高重建队列

toArray() 它是集合框架(特别是 List 接口)中常用的一个方法,用于将集合转换为数组
无参
返回一个包含集合所有元素的 Object 类型数组。
不能直接转换为原始类型数组(如 int[]、double[] 等)
有参,传入的是参数模板

Integer[] arr = list.toArray(new Integer[0]);
Integer[] arr = list.toArray(new Integer[list.size()]);

二叉树

DFS:递归,迭代(除了基础的还有一般统一的写法,不好理解,打算只记一种基础的)
BFS:层序遍历

Collections类是Java中针对集合类的一个工具类 reverse
和Arrays有点像,一个操作集合,一个操作数组

list当然能用增强for遍历啊,你在迷什么,三种:for,增强for,iterator

101.对称二叉树 反转二叉树

基本类型 int, double, char 拷贝值,互不影响
引用类型 String, Object, Array, TreeNode 拷贝引用,共用对象
对称做法:递归,队列(递归好做

116.填充每个节点的下个指针 117

peek 队列只取出不删除,如果是空队列则返回null
这种list两个之间进行比较的,写法是1+n-1,第一个元素单写,后面n-1写成循环的形式

104.二叉树的最大深度

迭代法:层序遍历的变体
递归法:比较简单

110.平衡二叉树

简单级别,但是感觉并不简单
递归函数要设置合理,-1表示不均衡,0表示该节点空,n表示高度为n

257.二叉树的所有路径

stringBuilder的用法还是不够熟悉

654.最大二叉树

递归好做,注意初始状态与递归状态的区别,初始状态不是空数组,但是递归后可能就是空数组了

106.从中序后序构造树

每次都新建数组,切割原数组,好理解但是性能不好
通过下标索引操作,性能好但容易搞混

700.二叉搜索树中的搜索

有的时候写if条件老是出现缺return条件的情况
虽然逻辑上 if 已经覆盖了所有情况,但 Java 编译器在静态检查时不会去计算 if 条件是否覆盖所有可能性,因此它会认为可能存在某些情况没有返回值

98.验证二叉搜索树

难点1:if条件怎么巧妙地合并一下
难点2:跨层级怎么比较,递归的方式无法做了
注意到性质:二叉搜索树的中序遍历是一个有序数组
判断时也要注意是二叉树必须得小于或者大于,等于不算
其他做法晚点看

530.最小绝对差

处理成list再去找最小差值有点慢,直接在递归遍历的时候找

众数

同理,直接在递归遍历的时候找

235 236.最近公共祖先

递归,想明白递归的每一步返回的是什么:在该子树中的最近公共祖先

450.删除二叉搜索树中的节点

递归的是子树中删除k值
终止条件是root节点值等于k值,删除时需要考虑左右子树是不是空,都不是空树时删除很巧妙,通过移动来做的删除

669.修剪二叉树

递归在返回树的左右子树时,所需要做的操作别忘了

如果if …… return 的话,可以并列写if条件
如果if ……修改root,最后return root,要写成if else的结构,要不然在第二个if条件判断的地方会报错空指针异常

    if (root.val < low) {  // 当前节点值小于low
        root = trimBST(root.right, low, high);  // 跳过当前节点和左子树,直接修剪右子树
    }
    if (root.val > high) { // 当前节点值大于high
        root = trimBST(root.left, low, high);   // 跳过当前节点和右子树,直接修剪左子树
    }
    return root;

这题比删除节点要简单的原因,就在于,一个节点不在范围中,他的左右子树一定有一个也不在范围,因此只用保留一个子树

538.转换累加树

简单

108.有序数组转换为二叉树

注意copyOfRange函数是左闭右开
public static int[] copyOfRange(int[] original, int from, int to)

二叉树总结

20.有效的括号

Deque 既可以用作栈(push/pop),也可以用作队列(offer/poll)。offer是队尾操作,其他都是队头操作
规避空指针(直接输入一个右括号)

if ( que.isEmpty()||ch != que.peek() ) 两个判断条件的前后顺序竟然也会影响

LinkedList 既实现了 List 接口,又实现了 Deque 接口,因此可以作为队列、栈或双向链表使用
LinkedList 类 虽然实现了 Deque 接口,同时也实现了 List 接口(支持 get(int)),但当你用 Deque 类型声明变量时,只能调用 Deque 接口的方法
在学习集合时都是list接口类型,因此一些方法,当linkedList用作deque接口实现类时候不能用。

150.逆波兰表达式

Integer.valueOf(s) string类型转换成integer类型
注意接口的命名要清晰易懂
string的遍历方式,toCharArray,for-each遍历

239.滑动窗口最大值

核心就是维护一个单调递减的双端队列,比如..5..4..,在5离开窗口之前最大值是5,在5离开窗口之后最大值才可能变成4
出窗口的值等于peek值时候可以队列出,入窗口的值大于队尾的值时,队尾出,要写成while循环,保证队尾比新值小的都出队尾完了之后,新值才入

344 541反转字符串

练习字符串的使用

卡55.右旋字符串

先整体,再局部的思想

28.找出字符串中第一个匹配项的下标

KMP算法
KMP算法对朴素匹配算法进行了改进,利用匹配失败时失败之前的已知部分时匹配的这个有效信息,
保持主串的 i 指针不回溯,通过修改模式串(子串)的 j 指针,使模式串尽量地移动到有效的匹配位置。该算法的时间复杂度为 O(n+m)

next数组的标准做法是求前缀和后缀的最长相等的长度

347.前k个高频元素

top k问题,大顶堆实现(小顶堆也可以)
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair2[1] - pair1[1]);
pair2[1] - pair1[1] 表示按第二个元素的降序排列(因为pair2在前,pair1在后,如果结果为正,pair2会排在前面)

回顾了下Entry的用法
java new数组,静态时候用{}

151.反转字符串中的每个单词

String 不可变,需转为 char[] 或 StringBuilder

对string的操作应该是在主方法中转换为char[],然后调用的方法都传参字符数组,最后主方法返回new String(ch)

459.重复的子字符串

两种解法:
1.拼接s+s,去除首尾字符(排除本身的干扰),如果在新字符串中能找到s,则说明是重复的
2.当最长相等前后缀不包含的子串的长度可以被字符串s的长度整除,那么不包含的子串 就是s的最小重复子串
属于想到性质了后实现很简单的类型
注意kmp算法中不匹配时可能需要回退多次 (while)

哈希表

349.两个数组的交集

hashset遍历:
1.增强for
2.iterator迭代器
3.java 8
4.stream API

声明时不添加泛型,HashSet set = new HashSet<>(); for(String item : set)遍历就会出错
当你不指定泛型时,集合会被视为包含 Object 类型元素,因此要进行foreach遍历要声明泛型

两数之和

map

三数之和

双指针,保证start<end就卡住其他的范围
整理了asList和toArray的用法
注意去重逻辑

四数之和

内层的去重j>i+1,保证不是起始点就行
整型移除问题
剪枝逻辑由于不是target不再是0,也发生变化

454.四数相加

set和map的contains的时间复杂度都是o(1),但是list的时间复杂度是o(n),这个题如果用contains时间复杂度又变成n^4
hashmap

链表

数组在内存中是连续分布的,但是链表在内存中不是连续分布的

反转链表

cur,prev两个指针,注意指针最后的位置
判断是否需要头结点
如果for循环边界不好判断的话,尝试用循环次数,从0开始,小于n,就循环了n次

k个一组翻转链表

上一题的翻转链表做n次,p每次的位置在变,需要找到p的新的位置,其实就是上一个p的next,在连接链表之前记录一下就可以

删除节点 237 19 82 83
876.中间节点 143.重排链表

21.合并两个有序链表

递归

148.排序链表

分治,递归的方法,递归深度是logn,每层合并的工作量是n,时间复杂度是nlogn
用到合并有序链表和找中间节点的知识
找中间节点,要找中间偏前面的节点,fast指针从head.next开始走

234.回文链表

1.递归做法
巧妙,利用递归调用栈保存的反向遍历的节点引用
时间复杂度o(n)
2.或者反转后半部分,比较前后是否相等
快慢指针找中间节点--反转后半部分--遍历比较

160.相交链表

双指针的做法很巧妙
其次可以对齐尾部,从公共长度部分开始遍历,这样做

211.最大正方形

首先是dp的定义要清晰,定义为以[i][j]为右下角的最大正方形的边长最好

其次是状态转移方程,从边长的角度考虑,一定是最小的那个正方形边长加1

最后要注意的是记录下循环过程dp数组中的最大值

215.topK问题

改进的快排
https://blog.csdn.net/qq_39181839/article/details/109478094

快排的几种方法:挖坑法,指针交换法(Hoare法),Lomuto法
Hoare法返回的是中间分界点 j,不保证 pivot 归位,Lomuto法返回的是 pivot 的最终位置
掌握两种好理解的,挖坑法和双指针法

堆排序

排序相关
image

hot100 一个月

155.最小栈

辅助栈,Queue单端队列,Deque是双端队列并且可以作为栈来使用
239.滑动窗口最大值
知道要写个类,但是写了一个奇怪的构造函数emm,直接定义一个队列,不写构造函数了
还有就是入队列和出队列的方式

链表相关题目

相交链表 return PA
回文链表,递归的写法太绕,选择取中间节点--翻转后半部分--前后段比较的方式来做
排序链表,选择断开链表的操作

树相关

记忆模板:二叉树的递归和迭代遍历,层序遍历

102 套用模板
538 二叉搜索树中序遍历的逆序是一个递减的数列
617 easy,也是遍历衍生题

posted @ 2025-03-15 15:59  huhulahu  阅读(23)  评论(0)    收藏  举报