剑指offer 分类刷题记录

  • 反思
    • 祖先
    • 深度
    • 子树
    • 层次遍历
    • 先序、后续遍历
    • 微软补充
  • 链表
    • 删除链表
    • 公共节点
    • 反转平移链表
    • 合并链表
    • 力扣补充
  • 数组
    • 微软
      • n数之和
      • 矩阵数组
      • 排序
    • 搜索
  • 字符串
    • 字符串与其他数值类型的转换
  • 动态规划
    • 简单
    • 打家劫舍
    • 买卖股票
    • 最大最长子系列
    • 二维数组
    • 字符串
    • 其他
  • 回溯(不熟)
    • 无序
    • 有序
    • 二维
  • 贪心

微软面经
剑指offer网址
牛客算法题题目类型总结
codetop
代码随想录pdf
刷题经验
时间复杂度
java数据结构的定义

反思

刷题慢 以及记不住 ,要动脑子 而不是图省事
且注重核心思路 而不要过分抠细节
需要锻炼想思路的能力+有思路的时候能否写出一个题目的能力
数组的话 感觉就是各种位置的变换(数学思维 前后i,j sort 二维数组 是row和col)
剑指offer 分类刷题记录_第1张图片

剑指offer 分类刷题记录_第2张图片
剑指offer 分类刷题记录_第3张图片

Java各种数据结构的定义

  • class、数值、指针、节点

  • 递归的空间复杂度一般就是 递归的层数,而在二叉树里面,递归的层数一般就是height

祖先

剑指 Offer 68 - II. 二叉树的最近公共祖先

  • 时间复杂度:O(n) 空间复杂度:O(height) 最大O(n)

BST中两节点的最近公共祖先 67

  • 时间复杂度:O(n) 空间复杂度:O(height) 最大O(n)

深度

子树最大深度55 最小深度111

  • 时间复杂度:O(n) 空间复杂度:O(height) 递归函数需要栈空间,而递归的深度取决于树的高度

平衡二叉树55

子树

另一个树的子树 572
树的子结构 26
镜像二叉树

  • 主函数中记得出口条件 root==null false
  • 子树和子结构,都是写一个函数 判断子树和root节点

层次遍历

  • TreeNode temp=que.poll();
  • node.next = queue.peek()

257. 二叉树的所有路径
剑指 Offer 32 - I. 从上到下打印二叉树
二叉树的层序遍历(把二叉树打印成多行 二维数组输出) 剑指 Offer 32 - II 102

  • 需要具体到每层,size for循环 两个容器即可

二叉树的锯齿形层次遍历(按之字顺序打印二叉树)剑指 Offer 32 - III. 103

Collections.reverse(List list)

二叉树的层次遍历 II(从底向上依次按行输出各层节点)107

data.addFirst(tmp)

116. 填充每个节点的下一个右侧节点指针

  • 递归
  • 层次遍历
  • node.next = queue.peek();

117. 填充每个节点的下一个右侧节点指针 II

  • 递归(跟上一个有不同)
  • 层次(跟116一样)

先序、后续遍历

剑指 Offer 33. 二叉搜索树的后序遍历序列

(数组题目)主函数输入:int[]
子函数输入:int[],left,right

数组知识点

  • 使用子函数(左右子树对应的数组范围一直在变 定义low、high)
  • 定义p指针:从left开始,遍历左子树找出mid(mid=p),判断右子树(if(p!=right))
  • 检查左右子树

根据(前序中序)(中序后序)构造二叉树 105 106

int[ ] leftpreorder=Arrays.copyOfRange(preorder,1,mid+1)

思想:

  • 建root节点
  • for循环找到分割数组的inorder的 index值
  • 构造数组,构造树
    int[ ] 新数组名 = Arrays.copyOfRange(旧数组名,下界,上界) 范围为:[下界,上界),上界取不到,如果没有这个函数直接for循环出四个数组
  • 不用新建函数 加入left和right递归需要用到的参数,因为是直接新建了数组了,所有每一次递归 inorder[0]的值是不同的。

路经总和的的三个题目112、113、437 (不熟)

  • 递归
  • 回溯

二叉搜索树中第K小的元素230 第k大元素 J54
993二叉树的堂兄弟节点

  • 找到x、y的父节点和深度

微软补充

找到树最左下角的节点的值 513

  • 层次遍历最下层,先入右节点再入左节点,最后node的就是 最下层最左边的节点
  • !que.isEmpty() Queue< TreeNode> que=new LinkedList<>();

二叉树的右视图 199

  • 思想:用一个集合存放每一层的最右边的节点值
  • 怎么具体到某一层的某个节点,用一个size for循环i=size-1的时候就好了
  • 只要涉及到以行为单位的,用层次遍历和for循环

一棵树每层节点的平均数 637

最长最大 路径相关系列—— 递归遍历 (root的处理在return那一句里面)
二叉树的直径 543

  • 直径,深度,同值路径,最大和路径——左右子树递归,root的处理一般放在return里面

二叉树的最长同值路径 687

  • 与直径不同并不是直接在return里面+1,而是在left和right里面判断+1(是否同值)

Leetcode124. 二叉树中的最大路径和

  • 有可能和是负值,这时候在left和right里面递归时判断left和0 的值的大小
  • return中加的不是1 而是root.val

求根到叶子节点数字之和 129(不熟)

  • 前序遍历
  • 用一个void subfunc更新全局变量val
  • subfun需要递归,因此增加一个(父节点的sum参数),叶子节点的时候更新all

450. 删除二叉搜索树中的节点 701. 二叉搜索树中的插入操作

  • 二叉搜索树,通过val值递归左右子树,然后处理root满足的情况

中序遍历相关
剑指 Offer 36. 二叉搜索树与双向链表
LeetCode 530.(二叉搜索树的最小绝对差)

  • 中序遍历

中序遍历的下一个子节点 剑指offer8 二叉树的下一个结点

  • 迭代
  • 有右子树去右子树里面找
  • 没有右子树 去父节点找

94. 二叉树的中序遍历(不熟)

  • 用一个void subfuc更改数组,否则递归可能出问题

验证树为BST 98

  • 先序遍历
  • 使用一个subfunc来更新min和max的值
  • 主函数Long.MIN_VALUE

二叉树:当前节点的值更新为当前节点所有子节点的值之和(递归和非递归)

链表

删除链表

if(node!=null && node.val) 有val 必须不为null
剑指offer18. 删除链表的节点(节点值不重复,只删除给定值)
删除排序链表中的重复元素 83
删除排序链表中的重复元素 II 82(不熟)
剑指 Offer 06. 从尾到头打印链表

删除链表的倒数第 n 个节点 19

找第倒数第k个节点fast走k(fast!=null)或者 fast走()
找第倒数第k+1个节点 fast走k-1(fast!=null) 或者 fast走k(fast.next!=null 可得到最后一个fast的值)

公共节点

剑指offer 52 两个链表的公共节点 简单
找出环形链表的入口节点 142

反转平移链表

25. K 个一组翻转链表

  • 做出需要翻转的那一段——翻转
  • 重新连接链表(四个指针)pre head tail tail.next

两两交换链表中的节点//反转链表 24、206(不熟)

  • 反转链表就是 调整指针的指向(更改一个指向即可)+ 节点的更新(pre,cur)利用temp
  • dummynode,交换节点 pre ,node1,node2三个指针

旋转平移链表 61 (链表每个节点向右移动 k 个位置)

  • 快慢指针 找到fast和slow slow.next
  • 找到(倒数第K+1个)且保证fast和slow都不为空
  • 找第倒数第k+1个节点 fast走k-1(fast!=null) 或者 fast走k(fast.next!=null 可得到最后一个fast的值)
    ListNode newhead=slow.next;
    fast.next=head;
    slow.next=null;
    return newhead;
  • 数组的平移就是 三段reverse

反转链表(反转指定位置的链表)92

  • 正常翻转 断链 翻转 连接
    定义指针 rightnode、leftnode、pre、succ、dummynode
  • 头插法
    dummynode
    pre(排好序的最后一个节点)
    cur(要插入的节点)
    (temp 断链连接的时候暂存的cur.next)

合并链表

合并两个有序链表 21

  • 递归

Leetcode23 合并k个排序链表

         for(int i=1;i

力扣补充

147. 对链表进行插入排序

  • dummynode
  • lastsorted(排好序的最后一个节点)
  • cur(需要插入的那个节点)
  • pre(用于在排好序的节点里遍历查找插入的位置)

Leetcode114. 二叉树展开为链表

  • 递归小tips,不知道如何处理根节点的时候,把左右子树想象成已经递归好的样子,比如这一个,左子树捋直了,右子树捋直了,只需要考虑怎么把左右子树接起来就行了

445. 两数相加 II

  • dummyHead
  • cur(新建的节点)
  • sum(总的值 sum%10、sum/10)

1290. 二进制链表转整数

sum*2+root.val

86 分隔链表(按照给定的值x)

  • 维护两个链表(dummynode),注意只是把原链表的值挂载到这两个链表上,而并非重新new链表值
  • 对node1的值进行更新、对head的值进行更新

328. 链表元素按奇偶位置聚集

  • (跟上边的86 一样,创造两个dummynode即可)指针的断链连接

234. 判断是否为回文链表

  • 断链(快慢指针)while(fast.next!=null&&fast.next.next!=null){ //找中间节点
  • 翻转(reverse)
  • 比较

143. 重排链表L0 → Ln → L1 → Ln-1 → L2 → Ln-2

  • 快慢指针找到断链的位置
  • 断链 把后半部分倒置
  • 把第二个链表分别插入前半部分(指针的指向)

数组

  • 数组函数
    System.arraycopy(int[] arr, int star,int[] arr2, int start2, length);
    int []newList = Arrays.copyOfRange(orial,0,5); [ )

数字反转

  • 考虑是否溢出
    lastsum=sum;
    sum=sum*10+temp;
    sum/10!=lastsum

287. 寻找重复数

  • 二分查找
  • 快慢指针

7.整数反转

  • 数字的操作sum=sum*10+x%10

9.回文数

  • 翻转后半部分数字
    revertedNumber = revertedNumber * 10 + x % 10
    x == revertedNumber || x == revertedNumber / 10
  • 变成字符串,判断字符串的回文(空间)
  • 翻转整个数字(溢出)

lc8. 字符串转换整数 (atoi)

  • 空格、±,数字(sum=sum*10+temp 考虑溢出 )
  • char[] ch=s.toCharArray()

微软

189. 轮转数组(向右移动k个位置)

  • 三次reverse
  • 修改原数组 System.arraycopy()
  • 生成新数组 Arrays.copyO

41. 缺失的第一个正数

  • 多种方法 时空复杂度的要求

31下一个排列(没太明白)

66 加一

  • 从后往前迭代 ,对于9和非9 的处理(进位)

136. 只出现一次的数字

  • 哈希表
  • 先sort for循环(+2)

55. 跳跃游戏

rightmost=Math.max(rightmost,i+nums[i)

n数之和

两数之和

有序 while循环+双指针
无序

  • 暴力:两重for循环
  • 一个 for循环:哈希表(内容,下标)边存nums[i],边找target-nums[i]

三数之和15(不太会)

  • 排序一下 for循环nums[i],对然后通过双指针从两边开始找 剩下的两个符合的 移动双指针

18. 四数之和

  • 两个for循环和 while(left,right)找到三个数的和

16. 最接近的三数之和

  • 同样是for循环和 while(left,right)找到三个数的和,找到最接近的值

leetcode 560. 和为 K 的子数组

  • 暴力:两重for循环
  • 前缀和+哈希(这个不太会)
    pre,pre-k

矩阵数组

矩阵的乘法
73. 矩阵置零

  • 行、列中一个为0,其余整行(列)均置0
  • boolean[] row 、col
  • 两个for循环,一次确定哪一行(列)有0,一次置0

48 旋转图像

  • 数学:先上下反转,然后对角线翻转

54. 螺旋矩阵

  • 生成二维数组 int[][] direction={{0,1},{1,0},{0,-1},{-1,0}};
  • total=rows*cols;
    boolean[][] visited
    int[][] direction={{0,1},{1,0},{0,-1},{-1,0}};
    int directIndex=0; row=0 col=0;
  • row=row+direction[directIndex][0] (但是要判断这个row是否合理,不合理的话 就要更改方向,也就是dirindex的值)

59. 螺旋矩阵 II

  • 在判断下一个row是否合理时
    54用的是一个矩阵boolean[][] visited)
    在59中用的是matrix[nextRow][nextCol] != 0

36. 有效的数独

排序

209. 长度最小的子数组

  • 满足子数组的和>= target的长度最小的连续子数组
  • ① 两个for 循环 分别固定好 start和end 找Math.min
  • 前缀和+ 二分查找(都是正数数组 所以前缀和是升序的)

75. 颜色分类

  • newstart=0;//代交换的开始位置(作用:前边的交换好了 就固定不动了)
  • 两次for循环,分别把0和1交换的前边来

数组中的第k个最大元素 215

  • 快排得出index
  • 与k进行比较(low=index+1,high=index-1)

J40最小的k个数(快排)

  • 快排:int partition(int[] nums,int low,int high)
  • while(true){
  • if( index?k-1 ) Arrays.copyOf(nums,k)
  • 与前边不同的就是Arrays.copyOf(nums,k)

剑指Offer21:调整数组顺序使奇数位于偶数前面

  • 不按相对顺序:快排(i,j)
  • 按相对顺序:两个队列

面试题61. 扑克牌中的顺子

  • Arrays.sort(nums)
  • < 5的长度

剑指 Offer 51. 数组中的逆序对

  • 归并排序
  • 计算left——right的长度(right-left+1)
    merge(nums,left,mid);
    mergeSort(nums,left,mid,right);

剑指Offer03:数组中重复的数字(与index对应)

  • 01244, nums[i]!=i(用于判断,符合直接跳过就好), num[i]==nums[nums[i]]
  • 交换nums[i]和nums[nums[i]]

搜索

JZ4 二维数组中的查找
寻找旋转排序数组中的最小值 153 特定值 33

  • nums[mid]和nums[right]比较,条件leftright)那个部分还是 后边那个部分(mid>right)= 直接返回,更新left或者right的值,
  • 找特定值的时候,先看是否相等,然后利用上边的判断哪边是有序的,还要去看target是否处于有序数组,否则去无序里面找

217. 存在重复元素

  • 直接两个for循环暴力看
  • sort之后在看
    Map

JZ53 数字在升序数组中出现的次数

  • for循环(复杂度大)
  • 二分查找

剑指Offer 39:数组中出现次数超过一半的数字

  • 1、使用库函数Arrays.sort,或者使用其他排序函数
  • 2、暴力 两层for循环,遍历每一个数字的次数
  • 3、哈希(数字,次数)

剑指Offer(三十二):把数组排成最小的数

pass

字符串

字符串、字符数组、字符串数组、字符、stringBuilder、数字
map函数、字符(大小写、判断是否是字母或数字)

  • 字符串(charAt、substring、trim、length()、equals)
    s = s.trim(); // 删除首尾空格
    ans.substring(0,j) —— ans是字符串(不包括结束索引)
    int n = s.length()
    s.charAt(i - 2) - ‘0’ — 字符转化为数字
    char temp=s[right];
  • 遍历字符串中的字符
    int n = s.length()
    s.charAt(i)==’ '(字符用引号)
    s.charAt(i - 2) - ‘0’ — 字符转化为数字
  • StringBuilder(new、append、reverse、tostring)
  • StringBuilder——改变字符串的内容
    StringBuilder res = new StringBuilder()
    res.append(s.substring(i + 1, j + 1) + " "); // 添加单词 append方法就是将字符串追加到当前StringBuilder实例的结尾
    res.toString()——把StringBuilder转换为字符串
  • sgood.toString().equals(sgood_rev.toString())
  • StringBuffer sgood_rev = new StringBuffer(sgood).reverse()
  • 转换为字符串(StringBuilder、char[]、List)
    res.toString()——把StringBuilder转换为字符串
    String str=String.valueOf(ch)— 字符数组转化为字符串
    data.add(new String(ch))—— List< String > data、char[] ch、(把字符数组 转换为字符串)
  • 字符串数组
    String[] strs
    strs[i].length()
  • 字符数组和字符串的转换(toCharArray()、String.valueOf( ))
    char[] ch=s.toCharArray()——字符串转化为字符数组
    String.valueOf(ch2) 字符数组转化为字符串s
  • Character.toLowerCase(ch)
  • !Character.isLetterOrDigit(s.charAt(left)) 判断字符是不是字母或数字
  • map函数(get、put、getOrDefault、containesKey)
    Map< , >map=new HashMap<>();
    map.containsKey(ch)
    map.put(ch, map.getOrDefault(ch, 0) + 1)
    dic.get(s.charAt(i)) == 1 (s是字符串)

344. 反转字符串(数组)

  • char temp=s[right];

43. 字符串相乘

  • 利用字符串相加(使用1个StringBuilder)
  • 主函数相乘(使用2个StringBuilder,一个是总结果,一个是每一位与乘数相乘之后的结果)
  • 两层3个for循环

415. 字符串相加

  • 两数相加、链表两数相加

22 括号生成

  • 递归
    data.add(new String(ch))—— List< String > data、char[] ch、(把字符数组 转换为字符串)

20.有效的括号

  • 使用栈和map
  • 右括号与栈顶元素匹配;左括号入栈
  • 结果:(不匹配、栈不为空)

125. 验证回文串

  • Character.toLowerCase(ch)
  • !Character.isLetterOrDigit(s.charAt(left)) 判断字符是不是字母或数字

剑指Offer 34:第一个只出现一次的字符

  • 存到map里面 dic.put(ch, dic.getOrDefault(ch, 0) + 1); < 字符,对应的个数>
    //get字符的value值,如果无,则defalut 0,返回个数 然后+1
  • 从map里面取 if (dic.get(s.charAt(i)) == 1)
    //直接 get 字符对应的value值

lc14最长公共前缀

  • 暂存第一个字符串,不断和下一个比较 使用ans.substring(0,j)缩短
  • 暴力:两个for循环

58. 最后一个单词的长度
剑指Offer(四十四):翻转单词顺序序列

    //先去掉空格
    //双指针法从后向前遍历,前边的指针遍历到空格停止(i+1,j+1)add到stringBuilder
    //然后处理两个指针,最终再次回到两个指针都指向单词最后一个的状态 i-- ,j=i

剑指Offer(二):替换空格

两个ch:数组的长度是固定的,因此需要新开一个数组

剑指Offer(四十三):左旋转字符串

  • 转化为char[],三次翻转,然后在转换为string

剑指Offer(五十二):正则表达式匹配

字符串与其他数值类型的转换

剑指Offer 53:表示数值的字符串
lc8. 字符串转换整数 (atoi)

  • 空格、±,数字(sum=sum*10+temp 考虑溢出 )

13. 罗马数字转整数
12. 整数转罗马数字

if(i<len-1&&map.get(s.charAt(i))<map.get(s.charAt(i+1))){
ans-=map.get(s.charAt(i));
else{
ans+=map.get(s.charAt(i));

动态规划

简单

跳台阶 10
斐波那契数 10
矩形覆盖

打家劫舍

打家劫舍 I 198
打家劫舍 II 213
打家劫舍 III 337

dp[i],偷下标为i的房屋的时候。偷到的最高金额

买卖股票

买卖股票的最佳时机121

  • dp[i][j]含义:下标为 i 这一天结束的时候,手上持股状态为 j 时,我们持有的现金数。j = 0,表示当前不持股;j = 1,表示当前持股。 int[][] dp = new int[len][2];
  • 递推公式:(买入就-prices[i],卖出就+prices[i],不同的i,price不同 用max找最大值)
    dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
    dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
  • 初始化: dp[0][0] = 0; dp[0][1] = -prices[0];

122. 买卖股票的最佳时机 II

  • dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);

最佳买卖股票时机含冷冻期309

  • 加一个dp[0][2]

买卖股票的最佳时机含手续费 714

  • 有手续费的时候就要看看最后一天卖出去 以及不卖出去 哪个更大了(卖出去有利润的同时 还有手续费)
  • return Math.max(dp[len - 1][0], dp[len - 1][1])
    188 困难 pass

最大最长子系列

152. 乘积最大子数组

  • MaxF[i]=Math.max(MinF[i-1]*nums[i],Math.max(MaxF[i-1]*nums[i],nums[i]));
  • MinF[i]=Math.min(MinF[i-1]*nums[i],Math.min(MaxF[i-1]*nums[i],nums[i]));

1143. 最长公共子序列

  • dp[i][j]长度为text1 ——i,text2——j的时候 的最长公共子序列
  • if(第i项和第j项相等)——dp[i][j]=dp[i-1][j-1]+1;
    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);

最大子序和 42

  • dp[n],以第n个数为结束点的子数列的最大和
    dp[i]=Math.max(dp[i-1]+nums[i],nums[i])

最长连续递增序列 674

  • dp[i],以下标为i的元素结尾的子序列长度
    简单,一个for循环
    dp[i]=dp[i-1]+1;

最长上升子序列 300

  • 两个for循环第二个用于找前i-1个位置 最长的序列长度
  • dp[i]=Math.max(dp[j]+1,dp[i]);

二维数组

119. 杨辉三角 II
120. 三角形最小路径和
剑指 Offer 47. 礼物的最大价值(下次注意分开处理的部分)
63. 不同路径 II
二维数组从左上到右下的路径数 62

  • dp[i][j]=dp[i][j-1]+dp[i-1][j];

二维数组从左上到右下的最小路径和 64

字符串

最长公共子串

  • dp[i][j]表示在较短字符串str1以第i个字符结尾,str2中以第j个字符结尾时的公共子串长度
  • if(str1.charAt(i-1)==str2.charAt(j-1))——dp[i][j]=dp[i-1][j-1]+1
    else{ dp[i][j]=0;

131. 分割回文串

  • 得到是否是回文子串的dp数组
  • if(dp[start][j]){
    temp.add(s.substring(start,j+1));
  • 通过回溯遍历所有的子串[[“a”,“a”,“b”],[“aa”,“b”]]

647. 回文子串

  • check一个是否是字符串 回文子串的个数
  • dp[i][j]表示s在[i][j]的子区间内是否是一个回文串
  • s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i + 1][j - 1])
  • ps:
    for (int j = 0; j < s.length(); j++)——右边界
    for 循环的顺序是for (int i = 0; i <= j; i++) —— 已右边界往前找所有的左边界
 if (s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i + 1][j - 1])) {
        dp[i][j] = true;
        count++;
                }

139. 单词拆分

  • dp[i] 前i个字符 是否可以被构成
  • wordDict.contains(s.substring(j,i))
  • contains判断集合List中是否包含某个元素
  • s.substring(j,i) 取出索引j到i-1的

32. 最长有效括号

  • 以第i个字符为结尾的最长有效括号括号的长度
  • s.charAt(i)= =‘) ’
    if(s.charAt(i-1)==’(’ —— dp[i]=(i>=2?dp[i-2]:0)+2
    if(s.charAt(i-1)= =‘?’ dp[i]=dp[i-1]+(i-dp[i-1]>=2?dp[i-dp[i-1]-2]:0)+2;//dp[i-1] sub子串的最长数,2最后一个)和前边的(组成的,dp[i-dp[i-1]-2] sub子串之前的最长括号
s.charAt(i)= =') '
if(s.charAt(i-1)=='('  —— dp[i]=(i>=2?dp[i-2]:0)+2
if(s.charAt(i-1)= =')'                   dp[i]=dp[i-1]+(i-dp[i-1]>=2?dp[i-dp[i-1]-2]:0)+2;//dp[i-1] sub子串的最长数,2最后一个)和前边的(组成的,dp[i-dp[i-1]-2] sub子串之前的最长括号

91.解码方法

  • dp[n]代表前n个字母的解码方式
    if(s.charAt(i-1)!=‘0’) —— dp[i]+=dp[i-1]
    if(i>1&&s.charAt(i-2)!=‘0’&& (s.charAt(i-2)-‘0’)*10+s.charAt(i-1)-‘0’<=26)——dp[i]+=dp[i-2]

JZ48 最长不含重复字符的子字符串(不熟)

  • //dp[n]代表以数组下表为n位置结尾时 最长不重复子串,dp[0]=1,new dp[n]
    s.charAt(j)!=s.charAt(i)
  • dp[i]=Math.min(dp[i-1]+1,i-j)
    } //j就是前一个重复的字符串的index
    // 通过比较dp[i-1]+1,i-j的大小 就可以比较出来最后一个字符是否有重复
    //1、如果dp[i-1]+1>i-j,那么dp[i-1]+1有重复 选i-j
    //2、如果dp[i-1]+1

lc5最长回文子串

  • 两层递归
    1、第一层是从2开始枚举子串的长度
    2、第2层是从0开始枚举左边界

剑指 Offer 46. 把数字翻译成字符串的情况(不熟)

char[] ch = String.valueOf(num).toCharArray()
dp[i] 第i位字符,翻译的个数

  • 类似于打家劫舍
 int n = (ch[i - 2] - '0') * 10 + (ch[i - 1] - '0');
if(n >= 10 && n <= 25)——dp[i] = dp[i - 1] + dp[i - 2];
 else——dp[i] = dp[i - 1];

其他

10. 正则表达式匹配

  • dp[i][j],字符串的前i个和前j个的匹配情况
  • if(*)
    else

背包问题
416. 分割等和子集

  • dp[i][j] 表示从数组[0,i]中选择若干个,可以是0个,是否存在一种选取方案 使得和为j

413. 等差数列划分

  • i i-1 i-2
  • if( 2*nums[i-1]==nums[i]+nums[i-2])
    dp[i]=dp[i-1]+1;
    else——dp[i]=0;

42. 接雨水
剑指 Offer 49. 丑数

  • int num2=dp[p2]*2,num3=dp[p3]*3,num5=dp[p5]*5
    dp[i]=Math.min(Math.min(num2,num3),num5)

不同的二叉搜索树 96

  • G[i] += G[j - 1] * G[i - j];

322 零钱兑换

  • Arrays.fill(dp, max);
  • for 循环计算每一个 i [0,sum]的dp[i],dp[i]=dp[i-coins[j]]+1
  • 需要找到最小的的,因此需要嵌套一个for循环 循环 coins[j] ——dp[i]=Min(dp[i-count[j]]+1)
  • 最终返回dp[sum]

回溯(不熟)

视频b站

  • 组合直接temp.add 去重用一个visited数组
  • 排序 需要swap + temp.add 去重用HashSet
  • 为什么排序使用的x而非i呢,因为再上一步swap(i,x)换位置了!!

93.复原IP地址

  • int[] anip=new int[4];
  • void dfs(String s,int SegId,int start)
    if(SegId= =4)/ if(s.charAt(start)==‘0’)

131. 分割回文串

无序

77. 组合 ——从n个中取,以k个为一组一共多少组

  • 一次递归就是一次for循环
  • 每次for循环的起始位置不一样,传入得startindex就是每次for循环的起始位置
        for(int i=startindex;i<=n;i++){ 
            temp.add(i);//选好第i个了
            subfunc(n,k,i+1);
            temp.remove(temp.size()-1);
        }
  • subfunc(n,k,i+1),
    为什么是i
    1、从startindex{1,2,3,4}开始选,首先选第一个 temp.add(i)选{1}{2}…,然后选后边的 此时后边的startindex变成了i+1(2,3,4)(3,4),而排序仍旧是startindex即{1,2,3,4},{1,2,3,4},{1,2,3,4}
    剑指offer 分类刷题记录_第4张图片

39. 组合总和——找到组合中 和为target的所有子集

  • 无重复的元素数组,数组中的元素可以使用多次 ,不能有重复的组合
    {1,2,3} 无序去重
  • for(int i=x;i { subfunc(nums,target,sum,i); }
  • subfunc中 :同一个元素可以使用多次 所以是i 而非i+1
    因为是组合,所以不考虑顺序 所以是i,而非x

40 组合总和2

  • 有重复的元素数组,数组中的元素只能使用一次,不能有重复的组合
    也就是说{1,2,3,1} 2 选第一个和第四个{1,1}和选第四个和第一个是一样的{1,1} 不可以 去重
  • subfunc(nums,target,i+1,sum,flag)
    1、数组中的元素只能使用一次,所以是i+1
    2、 因为是组合,所以是i而非x
    3、去重 这个还不太懂
  • 去重
    if (i > 0 && nums[i] == nums[i - 1] && !flag[i - 1])

78. 子集 —— 找出一个无重复元素集合的所有子集

  • 无重复的元素数组 找出一个集合的所有子集{1,2,4,5}
  • 没有结束条件,每一个节点都需要被记录下来

90. 子集 II有重复元素(需要去重)

  • 有重复的元素数组 找出一个集合的所有子集{1,2,1,4}

有序

257. 二叉树的所有路径
JZ38 字符串的排列(有一些函数不熟)

  • 去重
  • 两个容器跟其他的有所不同
    List< String > res = new LinkedList<>()
    char[] c
    res.add(String.valueOf (c ));
    剑指offer 分类刷题记录_第5张图片

46. 全排列

  • 待排列的数组元素不重复({1,2,3}不用去重)
  • 因为排列 所以是subfunc(nums,x+1)

47. 全排列 II

  • 待排列的数组元素有重复{1,2,1,3}——需要去重
  • HashSet< Integer > set = new HashSet<>();
    set.contains(c[i]) set.add(c[i])

二维

机器人的行走范围 剑指offer 13

  • 这个没有循环,因为走一遍判断即可,因为没有循环,所以也不必恢复
  • 需要一个数组来确定boolean值visited[][]

矩阵中的路径12

  • 循环在主函数里面,对于每一个(i,j)为起点的,进行判断
  • 不用visited 不然每一次还都得重新更新所有visited的值,直接把board的值先改掉,递归结束再改回来即可

95. 不同的二叉搜索树 II
22 括号生成

贪心

  • 局部最优推出全局最优

代码随想录pdf
11. 盛最多水的容器
55. 跳跃游戏
45. 跳跃游戏 II
455. 分发饼干
409. 最长回文串
56. 合并区间

207. 课程表

  • 队列、数组

210. 课程表 II

  • 同207 多一个result数组 作为结果

200. 岛屿数量

你可能感兴趣的:(Leetcode刷题汇总,前端,vue.js,javascript)