微软面经
剑指offer网址
牛客算法题题目类型总结
codetop
代码随想录pdf
刷题经验
时间复杂度
java数据结构的定义
刷题慢 以及记不住 ,要动脑子 而不是图省事
且注重核心思路 而不要过分抠细节
需要锻炼想思路的能力+有思路的时候能否写出一个题目的能力
数组的话 感觉就是各种位置的变换(数学思维 前后i,j sort 二维数组 是row和col)
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)
两数之和
有序 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]比较,条件left
right)那个部分还是 后边那个部分(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);
}
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 字符串的排列(有一些函数不熟)
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. 岛屿数量