更新中
Deque<Integer> deque=new LinkedList<>();
deque.push();
deque.poll();
Queue<Integer> queue=new LinkedList<>();
queue.add();
queue.pop();
Deque<Integer> deque=new LinkedList<>();
deque.add();
deque.peekFirst();
dequie.removeFirst();
deque.peekLast();
dequie.removeLast();
int[][] num=new int[][]{{9,87,6},{51,0,1,2},{3,2}};
Arrays.sort(num,new Comparator<int[]>(){
@Override
public int compare(int[] o1, int[] o2) {
return o1[0]-o2[0];
}
});
class Solution {
public boolean isNumber(String s) {
if(s == null || s.length() == 0) return false;
boolean isNum = false, isDot = false, ise_or_E = false;
char[] str = s.trim().toCharArray();
for(int i=0; i<str.length; i++) {
if(str[i] >= '0' && str[i] <= '9') isNum = true;
else if(str[i] == '.') {
if(isDot || ise_or_E) return false;
isDot = true;
}
else if(str[i] == 'e' || str[i] == 'E') {
if(!isNum || ise_or_E) return false;
ise_or_E = true;
isNum = false;
}
else if(str[i] == '-' ||str[i] == '+') {
if(i!=0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
}
else return false;
}
return isNum;
}
}
class Solution {
StringBuilder res;
int count = 0, n;
char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
public String printNumbers(int n) {
this.n = n;
res = new StringBuilder();
num = new char[n];
dfs(0);
res.deleteCharAt(res.length() - 1);
return res.toString();
}
void dfs(int x) {
if(x == n) {
res.append(String.valueOf(num) + ",");
return;
}
for(char i : loop) {
num[x] = i;
dfs(x + 1);
}
}
}
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length() + 1, n = p.length() + 1;
boolean[][] dp = new boolean[m][n];
dp[0][0] = true;
for(int j = 2; j < n; j += 2)
dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
for(int i = 1; i < m; i++) {
for(int j = 1; j < n; j++) {
if(p.charAt(j - 1) == '*') {
if(dp[i][j - 2]) dp[i][j] = true;
else if(dp[i - 1][j] && s.charAt(i - 1) == p.charAt(j - 2)) dp[i][j] = true;
else if(dp[i - 1][j] && p.charAt(j - 2) == '.') dp[i][j] = true;
} else {
if(dp[i - 1][j - 1] && s.charAt(i - 1) == p.charAt(j - 1)) dp[i][j] = true;
else if(dp[i - 1][j - 1] && p.charAt(j - 1) == '.') dp[i][j] = true;
}
}
}
return dp[m - 1][n - 1];
}
}
时间 |
做了哪些 |
总完成量 |
5.26 |
|
21 |
5.27 |
(1)三数之和 (2)最长公共前缀 (3)下一个排列 (4)乘积最大子数组 |
25 |
5.28 |
(1)最长不含重复字符的子字符串(2)最长回文子串(3)有效的括号 |
28 |
5.31 |
(1)二叉树的前序后序中序遍历(2)二叉树的深度(3)判断是否为平衡二叉树(3)从上到下打印二叉树 |
34 |
6.1 |
(1)排序数组(快排、归并排序)(2)J 约瑟夫问题(3)两个栈实现队列 |
37 |
6.3 |
(1)J 二叉搜索树的最近公共祖先(2)J 二叉树的最近公共祖先(3)J 字符串转化整数(4)J 构建乘积数组 |
41 |
6.4 |
股票专场 买股票的最佳时机I–IV (5)包含冷冻期(6)包含手续费 |
47 |
6.6 |
(1)J 实现两数相加(不用±*/)(2)J 求前n项和(3)J 判断数组是否为顺子 |
50 |
6.7 |
(1)J n个骰子的点数(2)J 滑动窗口的最大值(复习)(3)J 队列的最大值(4)J 翻转单词顺序 |
53 |
6.8 |
(1)J 左旋转字符串(2)和为s的两个数(3)和为s的整数序列(4)三数之和(复习) |
56 |
6.9 |
(1)J 数组中数字出现的次数I (2)II(3)二叉树的深度(4)判断是否为平衡二叉树(后面三复习) |
57 |
6.10 |
(1)J 二叉搜索树的第K大节点 (2)排序树组中查找数字I(3)0~N-1中缺失的数字(4)两个链表的第一个公共节点 |
61 |
6.11 |
(1)J 第一次只出现一次的字符 (2)J 丑数 |
63 |
6.16 |
(1)最长公共子序列(2)J 最长不含重复字符的子字符串(复习)(3)J 47 礼物的最大价值 |
65 |
6.17 |
(1)把数字翻译成字符串(2)把数字排成最小的数(3)数组序列中的某一位数字 |
68 |
6.18 |
(1)J 42 连续子数组的最大和 |
69 |
6.19 |
(1)J 1~n中1出现的次数(2)J 数组中最小的k个数 |
71 |
6.23 |
(1)J 30 包含main函数的栈(2)J 41 数组流中位数 |
73 |
6.28 |
(1)J 36 二叉搜索树与双向链表(2)J 51 数组逆序对 |
75 |
6.29 |
(1)J 34 二叉树中和为某一直的路径 |
76 |
7.1 |
(1)J 33 二叉搜索树的后序遍历(不熟练) (2)J 37 序列化与反序列化(3)J 31 二叉树的遍历I-III |
81 |
7.2 |
(1)J 31 栈的压入、弹出序列(2)J 29 顺时针打印矩阵 |
83 |
7.7 |
(1)J 26 树的子结构 (2)J 27 二叉树的镜像(3)J 28 对称二叉树(4)J 25 合并两个链表 |
87 |
7.8 |
(1) J 22 链表中倒数第k个节点(2)J 21 奇数位于偶数之前(3)J 20 表示数值的字符串 |
90 |
7.9 |
(1)J 18 删除链表中的节点(2)J 17 打印从1到最大的n位数(大数问题) |
92 |
7.12 |
(1)J 19 正则表达式匹配(动态规划,还得反复琢磨) |
93 |
7.14 |
(1)J 16 数值的整数次方 (2)J 15 二进制中1的个数(3)J 14-I 剪什字(数学推导)(4)J 14-II 剪什字(对结果取模) |
97 |
7.19 |
(1)J 12 矩阵中的路径(DFS+剪枝,/0表示空格) |
98 |
7.20 |
(1)J 13 机器人的运动范围 (深度优先搜索,定义两个方向向下、向右)(2)斐波那契数列(动规)(3)青蛙跳台阶(跟前面的起始参数不一样,前面的0,1,青蛙是1,1) |
101 |
7.22 |
(1)J 09 两个栈实现队列(创建一个辅助栈,一个负责删除,一个负责添加,删除的时候注意空判断)(2)J 08 从尾到头打印链表(辅助栈,后进先出的特性,递归,本质也是栈)(3)重建二叉树(递归) |
104 |
7.23 |
(1)J 03 数组中重复的数字(原地置换)(2)J 04 二维数组的查找(时间复杂度为0(M+N))(3)J 05 替换空格 |
107 |
7.26 |
(1)机器人的运动范围,可以缩小为向下和向右移动,维护一个队列,先进先出add和poll,每次循环两次,判断是否可达,加入队列(2)二进制中1的个数,n&(n-1)可以把n的低位的1变为0,例如110&101=100,利用这个性质计算1的个数(3)数值的整数次方,不需要考虑大数问题时,可转化为二分问题,每次需要判断b是奇数还是偶数,是奇数的话先乘以x,每次x>>1;二分的时间复杂度为logn。(4)打印从1到最大的n位数,考虑大数问题 |
|
一、数组
序号 |
题目 |
笔记 |
1 |
01 两数之和 |
hash遍历 O(N) O(1) |
2 |
J 56-II 数组中数字出现次数 66666666666 |
(1)采用状态机来做,异或的思想,加起来对3求余数,为00 01 10,先计算低位,在计算高位,one=one异或num与two,two=two^num&one 最后返回one(2)遍历统计。创建一个长度为32的数组,统计数组中的和,count[i]+=num&1;num>>>=1;然后恢复为整数。res=0,m=3 res<<=1,res |
3 |
14 最长公共前缀 |
(1) 横向扫描,依次比较 时间复杂度O(mn),空间复杂度O(1);(2)二分查找,l=0,r=minlen,mid=(r-l+1)/2+l.如果满足的话l=mid,否则r=mid-1。每次取一个字符串的一半,判断是否都存在,不存在,缩小范围,存在的话,就扩大范围,时间复杂度:O(mnlogm),其中 mm 是字符串数组中的字符串的最小长度,nn 是字符串的数量。二分查找的迭代执行次数是 O(logm),每次迭代最多需要比较 mnmn 个字符,因此总时间复杂度是 O(mnlogm),空间复杂度O(1) |
4 |
J 03 数组中重复的数字 |
原地置换,保证nums[i]=i,if(nums[nums[i]]==nums[i]) return nums[i];否则交换两个元素 |
5 |
15 三数之和 |
采用排序加双指针,其中第一次枚举和第二次枚举都需要去重,不能跟上次的一样,否则直接continue;需要注意的是,在双指针判断的时候,当双指针重合时,可以直接跳出循环,避免后续的操作! 时间复杂度O(N*N),空间复杂度O(logN),注意事项(1)在内循环的时候,j=i+1开始,(2)内循环判断两数字和,当小于目标值时,要使用while循环(3)当两个指针重合时,直接break。 |
6 |
31 下一个排列 |
(1)从后往前,找出满足nums[i].=0的条件下,从后往前找第一个>nums[i]的元素,找到以后交换nums[i]和nums[j];(3)此时[i+1,n)的元素满足降序,使用双指针进行排序。时间复杂度为O(N),空间O(1) |
7 |
912 排序数组 |
在快排的时候,while条件为l
|
8 |
J 62 约瑟夫环问题 |
(1)采用list,先存储1-n,定位idx=0,更新idx=(idx+m-1)%n,list.remove(idx),n–;此方法空间复杂度为O(n),时间复杂度为O(n*n),每次删除的时间复杂度为0(n),删除了n-1次。(2)数学公式解法:(当前idx + m) % 上一轮剩余数字的个数,最后一轮剩下两个数,从2开始反推,i<=n |
9 |
J 66 构建乘积数组 |
上下三角矩阵,先计算下三角,在计算上三角,注意值的更新,下三角时b[i]=b[i-1]a[i-1],下三角时,tmp=a[i+1],b[i]*=tmp. |
10 |
J 61 扑克牌中的顺子 |
(1)判断数组中最大值与最小值的差是否<5(2)两种情况特殊考虑,一是当数组元素为0时,直接continue,二是重复数字的去重,重复数字会影响最后的结果。 |
11 |
J 57-I 和为s的两个数 |
双指针,首尾指针 |
12 |
J 57-II 和为s的连续整数序列 |
双指针,开始两个。两个注意事项(1)在判断为相等时,记住左指针还要+1;(2)最后List转数组,res.toArray(new int[res.size()][]); |
13 |
J 53-I 排序树组中查找数字I |
(1)先找右指针,再找左指针,判断条件的时候,是l<=r,最重要的是nums[mid]<=target时,l=mid+1;而在找左指针的时候,是nums[mid]
|
14 |
J 53-II 0~N-1中缺失的数字 |
相当于找当前数字右边界,参考上题,当nums[mid]==mid时,l=mid+1.否则r=mid-1 |
15 |
J 40 数组中最小的k个数 |
维护一个大顶堆 ,也就是队列,大数字放前面。时间复杂度:O(nlogk),其中 n 是数组 arr 的长度。由于大根堆实时维护前 k 小值,所以插入删除都是O(logk) 的时间复杂度,最坏情况下数组里 n个数都会插入,所以一共需要)O(nlogk) 的时间复杂度。空间复杂度:O(k),因为大根堆里最多 kk个数。 |
16 |
J 29 顺时针打印矩阵 |
按层模拟,时间复杂度0(mn),空间除了输出之外,没有其他,注意在模拟后两个的时候,要加判断条件,left
|
二、链表
序号 |
题目 |
笔记 |
1 |
160 找出两个链表的交点 |
采用双指针法,两个指针分别指向两个链表的头结点,依次向后面,直到两个值相等,当到达各自尾部的时候,指向对方的头部O(M+N) O(1) |
2 |
J 24 反转链表 |
迭代 O(N) O(1) 递归 O(N) O(N)其中N是链表的长度复杂度主要取决于递归调用的栈空间,最多为 n 层 在while循环中,先计算next,然后curr.next=pre;pre=curr;curr=next,最后返回pre。 |
3 |
21 合并两个有序链表 |
|
4 |
83 从有序链表中删除重复节点 |
一次遍历O(N) O(1)比较本身和他下一个值的大小,相等,将它的next指针指向像一个的下一个,否则,curr=curr.next |
5 |
J 52 两个链表的第一个公共节点 |
浪漫相遇,双指针分别遍历,走到头时,到对方的头,当然,此时的判断条件就为A!=B |
6 |
J 25 合并两个链表 |
时间复杂度0(M+N),空间0(N) |
7 |
J 22 链表中倒数第k个节点 |
双指针,注意在while循环的时候,条件为fast!=null,最后返回slow。 |
8 |
J 18 删除链表中的节点 |
一次遍历,先执行空判断,当head=null或者head.val=val时,单独处理。while循环curr.next!=null&&curr.next.val==val,执行指针移动,最后判断一下curr的next是否为空,是的话删除节点,否则直接返回head。 |
三、字符串
序号 |
题目 |
笔记 |
学习状态 |
1 |
20 有效括号 |
(1)判断字符串的长度是否为奇数或者字符串为空;(2)创建一个map。存储对应的括号,key存储右括号,value存储左括号;(3)创建一个栈,用来存储左括号;(4)遍历,当map中存在时,判断括号是否匹配,匹配,记得出栈,否则,为左括号,直接加入栈。时间复杂O(N),空间复杂度O(n+m),m为hash表的空间。 |
|
2 |
5 最长回文子串 |
中心扩展法,注意左右边界的更新 start=i-(len-1)/2;end=i+len/2;时间复杂度:O(n^2)其中 n 是字符串的长度。长度为 1 和 22的回文中心分别有 n 和 n−1 个,每个回文中心最多会向外扩展 O(n) 次。空间复杂度O(1) |
|
3 |
J 48 最长不含重复字符的子串 |
采用动态规划+hash表,hash表储存char以及他们的索引;初始化左指针为-1(解决字符串为空的情况),右指针遍历字符串;当hash表中存在该字符的时候,更新i为索引和它本身的最小值;没有则表示第一个出现,加入hash表,更新结果为j-i和它本身取最大,空间复杂度map最大128,则为O(1),时间为O(N)。 |
|
4 |
459 重复的子字符串 |
KMP算法:(1)在原字符串前面加空格,初始化一个next[]数组;(2)for循环遍历,i=2,j=0;i<=len,此len为原字符串长度;(3)当j>0并且c[i]!=c[j+1]时,让j=next[j];(3)如果c[i]==c[j+1],j++;(4)最后让next[i]=j;(5)判断时首先判断next[len]>0并且len%(len-next[len])==0,才算true,否则false。 |
|
5 |
214 最短回文串(在字符串前面添加字符串使它成为回文) |
|
|
6 |
J 58-I 翻转单词顺序 |
在Java中,以空格为分割符完成字符串分割后,若两单词间有 x > 1个空格,则在单词列表 strs中,此两单词间会多出 x−1 个 “空单词” (即 “” ),去除string首尾空格并以空格分割,遍历字符数组,遇到“”直接跳过,否则,添加到stringbuilder,注意还得加一个空格。时间空间复杂度均为0(N) |
|
7 |
J 58-II 左旋转字符串 |
(1)字符串拼接(2)StringBuilder。时间空间复杂度均为0(N) |
|
8 |
J 50第一次只出现一次的字符 |
用HashMap存储频数,时间复杂度0(N),空间0(小写字符的个数),两次遍历字符串,它的value为一个boolean值,dic.put(c,!dic.containsKey©);第一次加入,为true,之后在加入,就是false,在堆字符串进行遍历,找到第一个为true的即可。 |
|
9 |
J 20 表示数值的字符串 |
依次判断,是否为数字,小数点,e,正负号。注意分析对 |
|
四、树(二叉树面试题)
序号 |
题目 |
笔记 |
1 |
144 二叉树的前序遍历 |
采用递归,时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。 |
2 |
94 二叉树的中序遍历 |
采用递归 |
3 |
145 二叉树的后序遍历 |
采用递归 总结遍历:只需要将res.add(root.val)进行位置的移动,放在迭代左节点的前,后,以及迭代右节点的后 |
4 |
J 55 I 二叉树深度 |
后序遍历(DFS)时间复杂度 O(N): N 为树的节点数量,计算树的深度需要遍历所有节点。空间复杂度 O(N) : 最差情况下(当树退化为链表时),递归深度可达到 N |
5 |
J 55 II 平衡二叉树 |
先序遍历+判断深度;先判断根节点是否为平衡二叉树,在判断左子树和右子树,采用树的深度,左右字数的高度差<=1,时间空间复杂度和上边一样(三个与,判断根节点,根节点的左子树,右子树)。 |
6 |
J32 I 从上到下打印二叉树(打印到一个int数组) |
二叉树的广度优先搜索(BFS),借助队列的先进先出的特性时间复杂度 O(N) : N 为二叉树的节点数量,即 BFS 需循环 N 次。空间复杂度 O(N): 最差情况下,即当树为平衡二叉树时,最多有 N/2 个树节点同时在 queue 中,使用 O(N) 大小的额外空间。 |
6 |
J 68-I 二叉搜索树的最近公共祖先 |
(1)curr==root(2)用一个while–true循环;(3)利用二叉搜索树的性质,当两个值逗比curr小,curr=curr.left,都大的话curr=curr.right,否则break; |
7 |
J 54 二叉搜索树的第K个最大值 |
二叉搜索树的性质:中序遍历为递增序列,那么中序遍历的倒序即为递减序列。递归调用k次,返回第k次的结果,当退化为链表时,时间空间复杂度都为0(N) |
8 |
J 34 二叉树中和为某一直的路径 |
深度优先搜索,时间复杂度:O(N *N ),其中 N 是树的节点数。在最坏情况下,树的上半部分为链状,下半部分为完全二叉树,并且从根节点到每一个叶子节点的路径都符合题目要求。此时,路径的数目为 O(N),并且每一条路径的节点个数也为 O(N),因此要将这些路径全部添加进答案中,时间复杂度为 O(N^2)。空间复杂度:O(N),其中 N 是树的节点数。空间复杂度主要取决于栈空间的开销,栈中的元素个数不会超过树的节点数。 |
9 |
J 33 二叉搜索树的后序遍历 |
辅助单调栈,后序遍历的倒序,每次遇到递减的节点,通过出栈来更新节点的父节点。如果当前节点大于root,直接返回false,否则如果栈不为空,并且栈顶元素大于当前元素的值,执行出栈,不断更新root,最后执行完了返回true。 |
10 |
J 37 序列化与反序列化 |
层序遍历的思想,注意是字符串,不难。 |
11 |
J 31 二叉树的层序遍历 |
在I的时候,是一个数组,直接加里面,层序遍历的时候,要考虑每一层放一起,需要用额外的一次循环,单独处理,倒序的时候,需要判断list的大小,看是插入头部,还是尾部,用一个双端队列 |
12 |
J 26 树的子结构 |
先序遍历加递归,递归终止条件为B为null,说明匹配完成,返回true,A==null或者a.val!=b.val 返回false,直接再次递归 判断AB的左右子树。最后,在函数中直接返回,首先保证Ab都不为空,B是A的子树,B是A的左子树的子树,B是A的右子树的子树。这两个都是走外层函数,不走递归。时间复杂0(MN),先序遍历树 AA 占用 O(M),每次调用 recur(A, B) 判断占用 O(N)。空间复杂度O(M)。 |
13 |
J 27 二叉树的镜像 |
两种思路,第一种递归,第二种,借助辅助栈,时间空间复杂度都为o(N) |
14 |
J 28 对称二叉树 |
递归,首先判断A.val和B.val是否相等,A.left.VALB.right.val;A.right.VALB.left.val.时间空间复杂度都为0(N)。 |
五、栈和队列(栈和队列经典面试题)
序号 |
题目 |
笔记 |
1 |
J 09 用两个栈实现队列 |
stack存储元素,实现向队列尾部添加元素,需要删除头部的时候,从stack1向2移动,全部移动完成,返回stack2队首元素,当然,刚开始还需要先判断Stack2是否为空,不为空,直接pop |
2 |
J 59-II 队列的最大值 |
维护一个单调的双端队列,三个操作(1)取最大值,让双端队列的队首元素出栈,当然首先需要判断是否为空;(2)向尾部添加,单调队列直接添加,双端的得判断后面元素是否小于当前值,出栈;(3)删除队首元素。单调的直接删除返回,双端的判断删除的队首元素是否为最大值,否则,双端队列队首元素也得出栈。时间复杂度0(1),空间复杂度0(N)。 |
3 |
J 30 包含main函数的栈 |
辅助栈,存储一个单调递减的栈,求min()时候,直接辅助栈pop() |
4 |
J 41 数组流中的中位数 |
维护一个大小顶堆,大顶堆存储小的,小顶堆存储大的,时间复杂度0(logN),堆的插入和弹出操作都是0(logN),空间复杂度0(N) |
5 |
J 31 栈的压入、弹出序列 |
借助一个辅助栈,将push的都压入栈中,当栈不为空,并且栈顶元素等于pop[i]中的元素时,i++,执行出栈。最后看栈是否为空。 |
六、哈希
七、图
八、位运算
序号 |
题目 |
笔记 |
1 |
J 56-I 数组中数字出现的次数 |
采用分组异或的思想(1)对所有的数进行异或操作;(2)找出低位不为0的数,作为标准;div=1,不断和ret进行按位与,直到不等于0(3)遍历数组,与div进行与操作,等于0是一组,不等于0又是一组,分别于a和b进行异或,最后得到的a,b就是答案。 |
九、非常规题目
算法思想
一、双指针、滑动窗口
序号 |
题目 |
笔记 |
1 |
J 59 滑动窗口的最大值 我是一个酸菜鱼,又酸又菜有垃圾 |
(1)初始化一个长度为n-k+1的数组,以及双端队列;(2)初始化长度为k的两个指针,左指针记为i=1-k,右指针为j=0;(3)进行循环for(int i=1-k,j=0;j=0,则ans[i]=队首元素。时间复杂度O(N),空间O(k) |
2 |
141 判断链表是否有环 |
慢指针指向head,快指针指向head.next,while下面加判断fast!=null |
3 |
142 链表环的入口 |
快慢指针指向head,while循环条件为fast!=null;慢指针每次向后移动一个,快指针先判断fast.next!=null,满足,移动两个,否则返回空;当快慢指针相等的时候,在拿一个指针指向head,慢指针与当前指针同时向后移动一个,直到相等,返回随便一个 时间0(N),空间0(1) |
4 |
J 57 和为s的连续正序列 |
左指针l=1,右指针为r=2,while循环条件为lres.toArray(new int[res.size()][]); |
5 |
11 盛水最多的容器 |
双指针 指向左右两边,每次移动最小的 相等移动左边 O(N) O(1) |
6 |
26 删除有序数组的重复项 |
快慢指针都初始化为1,慢指针表示要填入数字的下标,即代表结果,判断nums[fast] 和nums[fast - 1],不相等则填入慢指针中,相等f++ |
7 |
两个数组的交集 |
先进行排序。初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 pre ,将该数字添加到答案并更新pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。时间O(mlogm+nlogn) 空间O(logm+logn) 主要是排序消耗 |
8 |
J 21 奇数位于偶数之前 |
注意,在内层while循环中判断的时候,都要有一个前提条件,left
|
二、回溯
序号 |
题目 |
笔记 |
1 |
46 全排列 |
先判断tmp的大小是否等于数组的大小,否则,遍历,遍历前判断tmp.contains(),完了在回溯时间复杂度O(n*n!),空间复杂度O(n) |
三、动态规划
序号 |
题目 |
笔记 |
1 |
983 最低票价 |
(1)自后向前,如果当天不是旅游日,则dp[i] = dp[i + 1], 如果是旅游日,则为dp[i + 1] + cost[0] 、 dp[i + 7] + cost[1]、dp[i + 30] + cost[2]中的最小值 (2) 优化,自前向后,依次填表,分析当前的状态,) |
2 |
221 最大正方形 |
当前值的状态与它的左、上以及左上的元素有关,取他们的最小值然后加1****(千万别忘了+1),注意边界情况,时间复杂度以及空间的复杂度都为O(MN) |
3 |
62 机器人不同路径,总路径数 |
先初始化第一行和第一列都为1,矩阵其他元素的值为它左边和上边值的和时间复杂度以及空间的复杂度都为O(MN) |
4 |
64 最小路径和 |
直接在原数组上进行动态规划,和62题思路一样 空间复杂度为0(1)时间O(MN) |
5 |
303 数组区间和 |
重要的是思想,建立一个数组,用来记录从头到当前位置的和 |
6 |
79 单词搜索 |
向四个方向进行搜索,进行判断。每次搜索前将char数组对应值+256,完成之后-256,不需要额外的空间 |
7 |
152 乘积最大子数组 |
考虑到负数存在的情况,需要维护两个值,即正数的最大值以及负数的最小值.(注意在循环的时候,是mx乘nums[i],mn乘nums[i]以及nums[i]三者取最值)时间复杂度为O(N),空间复杂度为O(1)。 |
8 |
J 63 买股票I |
维护两个变量,然后更新,更新规则,刚开始sell=0是因为我们可以在同一天买入并且卖出,所以收益为0.chi=Math.max(chi,-prices[i]); buchi=Math.max(buchi,chi+prices[i]) |
9 |
122 买股票 II |
因为允许多笔交易,跟I就一个区别,chi=Math.max(chi,buchi-prices[i]) |
10 |
123 买股票 III |
维护两组变量,其中,两组中的buy都要是-prices[0],更像是把前面的两道题结合在一起。chi1=Math.max(chi1,-prices[i]); buchi1=Math.max(buchi1,chi1+prices[i]);chi2=Math.max(chi2,buchi1-prices[i]); buchi2=Math.max(buchi2,chi2+prices[i]); |
11 |
122 买股票 IV(最多完成k笔) |
buy[i][j]表示第i天进行了j笔交易并且当前手上持有一张股票。**sell[i][j]则表示在第i天进行了j笔交易。**初始化两个数组,buy[]以及sell[],长度为k+1,这儿的k=Math.min(k,n/2);buy[0]=-prices[0],sell[0]=0,其他位置都为Integer.MIN_VALUE/2;双重for循环,i=1;ibuy[0] = Math.max(buy[0], sell[0] - prices[i]);j=1;j<=k;buy[j] = Math.max(buy[j], sell[j] - prices[i]);sell[j] = Math.max(sell[j], buy[j - 1] + prices[i]);最后返回的结果Arrays.stream(sell).max().getAsInt(); |
12 |
309 买股票包含冷冻期 |
维护三个状态 f0为目前持有一支股票,f1目前不持有任何股票,并且处于冷冻期中,f2目前不持有任何股票,并且不处于冷冻期中,这里的处于冷冻期指的是第i天结束之后处于冷冻期。**newf0=Math.max(f0,f2-prices[i]);newf1=f0+prices[i];newf2=Math.max(f2,f1);**最后返回Math.max(f1,f2) |
13 |
309 买股票包含手续费 |
只需要在II的基础上扣除手续费即可。 |
14 |
J 60 n个骰子的点数 |
(1)采用动态规划的思想,维护投n-1个骰子的概率,(2)初始化dp数组,值都为1/6(3)三层for循环,第一层为骰子的个数,从2开始,然后来一个动态的数组,大小为5i+1,第二层for循环遍历dp数组,第三层遍历第n个骰子可能出现的骰子点数,tmp[k+j]+=dp[j]/6.0(4)时间复杂度0(n*n),空间0(n) |
15 |
J 49 丑数 |
定义三个指针,初始化dp数组,dp[1]=1,三个指针的分别乘以2 3 5,取最小值,然后看取得那个数,对应的指针++ |
16 |
最长公共子序列 |
建立一个(m+1)*(n+1)的数组,维护两个状态方程。(1)当s1(i-1)==s2(j-1)时,dp[i][j] = dp[i - 1][j - 1] + 1;否则dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);时间空间复杂度都为MN。 |
17 |
J 47 礼物的最大价值 |
|
18 |
J 42 连续子数组的最大和 |
此时刻的最大值和前一个时刻有关系,若dp[i-1]本来就是负的,则产生了负影响,dp[i]=nums[i],否则dp[i]=nums[i]+dp[i-1]。 |
四、数学计算
序号 |
题目 |
笔记 |
1 |
J 65 不用加减乘除实现两数相加jklgxh |
(1)无进位和n=a^b,进位和c=(a&b)<<1;(2)让进位和为0,那么就可以得到最后的结果为无进位和的值;(3)c=(a&b)<<1;a异或=b,b=c,最后返回a(4)时间和空间复杂度都为0(1),最大数为0x7fffffff,最多循环32次 |
2 |
J 64 求1—n的和 |
两种方法:(1)递归法:flag= n>0&&(n+=sumNums(n-1))>0,最后返回n,时间复杂度为0(N),函数递归n次,每次为0(1)。递归函数的空间复杂度取决于递归调用栈的深度,这里递归函数调用栈深度为 O(n)O(n),因此空间复杂度为 O(n)O(n)。(2)快乘法,将 B 二进制展开,如果 B 的二进制表示下第 i 位为 1,那么这一位对最后结果的贡献就是 A*(1< 0) && (ans += A) > 0; A <<= 1;B >>= 1; |
3 |
J 43 1-n中1出现的次数 |
当前位为0时,res+=highdigit,为大于1的,res+=highdigit+low+1,为1时,res+=(high+1)*digit,注意循环条件为curr!=0或者high!=0,时间复杂度logn,空间0(1) |
4 |
J 16 数值的整数次方 |
二分法,每次都需要判断n是否为奇数,时间复杂度0(logN),空间0(1) |
5 |
J 15 二进制中1的个数 |
采用优化位运算,每次将n=n&(n-1),也就是将n的低位的1变成0,在n成为0之前,计算轮数即可。时间复杂度:O(logn)。循环次数等于 n 的二进制位中 1 的个数,最坏情况下 n 的二进制位全部为 1。我们需要循环 logn 次。空间复杂度:O(1),我们只需要常数的空间保存若干变量。 |
五、数据库
1.四大排名函数和关键字
1.1 ROW_NUMBER()
- 在排名是序号 连续 不重复,即使遇到表中的两个一样的数值亦是如此
select *,row_number() OVER(order by number ) as row_num from num


1.2.rank()
Rank() 函数会把要求排序的值相同的归为一组且每组序号一样,排序不会连续执行
select *,rank() OVER(order by number ) as row_num from num

1.3.dense_rank()
Dense_rank() 排序是连续的,也会把相同的值分为一组且每组排序号一样
select *,dense_rank() OVER(order by number ) as row_num from num

1.4. ntile()
Ntile(group_num) 将所有记录分成group_num个组,每组序号一样
select *,ntile(2) OVER(order by number ) as row_num from num

2.多表级联
多表的联结又分为以下几种类型:
- 左联结(left join),联结结果保留左表的全部数据
- 右联结(right join),联结结果保留右表的全部数据
- 内联结(inner join),取两表的公共数据
序号 |
题目 |
SQL |
1 |
分数排名 |
select Score,dense_rank() over(order by Score desc) 'Rank' from Scores |
2 |
组合两个表 |
select p.FirstName,p.LastName,a.City,a.State from Person as p left join Address as a on p.PersonId=a.PersonId |