再更新
文章目录
- 7.28
- 7.29
- 7.30
- 8.1
- 8.2
- [58. 最后一个单词的长度](https://leetcode-cn.com/problems/length-of-last-word/)
- [53. 最大子序和](https://leetcode-cn.com/problems/maximum-subarray/)
- [25. K 个一组翻转链表](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/)
- [29. 两数相除](https://leetcode-cn.com/problems/divide-two-integers/)
- [44. 通配符匹配](https://leetcode-cn.com/problems/wildcard-matching/)
- [98. 验证二叉搜索树](https://leetcode-cn.com/problems/validate-binary-search-tree/)
- 8.6
- 8.7
- [169. 多数元素](https://leetcode-cn.com/problems/majority-element/)
- [309. 最佳买卖股票时机含冷冻期](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
- [226. 翻转二叉树](https://leetcode-cn.com/problems/invert-binary-tree/)
- [146. LRU缓存机制](https://leetcode-cn.com/problems/lru-cache/)
- [238. 除自身以外数组的乘积](https://leetcode-cn.com/problems/product-of-array-except-self/)
- [543. 二叉树的直径](https://leetcode-cn.com/problems/diameter-of-binary-tree/)
7.28
模拟笔试题1 – 能否被子字符串构成?
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
因为问的是子串是否可以构成原字符串,所以子串的最大长度是原来长度的一半。最开始想错了,认为满足条件的子串的长度只能是偶数,所以没跑过。但其实也有可能是奇数。所以每次都尝试看看能不能构成原字符串。(length --)
class Solution {
public boolean repeatedSubstringPattern(String s) {
if(s == null || s.length() == 0){
return false;
}
int length = s.length() / 2;
while(length > 0){
String temp = s.substring(0, length);
int len = 0;
int index = s.indexOf(temp);
while(index != -1){
index = s.indexOf(temp, index + length);
len += length;
}
if(len == s.length()){
return true;
}
length--;
}
return false;
}
}
模拟笔试题2 – 数组旋转
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
先整体翻转,以k位置为分割位,分别翻转前后的数组序列。
其中需要注意的是要先对输入的k进行处理,以防止输入的k大于数组的长度。
class Solution {
public void rotate(int[] nums, int k) {
if(nums.length == 0 || k <= 0){
return ;
}
int n = k % nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, n - 1);
reverse(nums, n, nums.length - 1);
}
public void reverse(int[] nums, int begin, int end){
while(begin < end){
int temp = nums[begin];
nums[begin] = nums[end];
nums[end] = temp;
begin++;
end--;
}
}
}
模拟笔试题3 – 最长的交叉路径(1372. 二叉树中的最长交错路径)
难度中等
最开始以为是父节点需要用到子节点的信息,新建了一个内部类来返回内部信息。不过发现那样的做法有问题。(其实应该是我返回信息不完整)
这个题一眼看上去就是深度遍历的问题,不过好好思考了一下,可以用一个数组来返回信息。就像打家劫舍系列的第三题(还是第四题?)。在这个题中dfs会返回一个数组(长度为2),其中0表示左树的交叉最大长度,1表示右树的交叉最大长度。在每次返回的时候都尝试去更新maxPath,最后得到的maxPath就是我们的答案。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int maxPath = 0;
public int longestZigZag(TreeNode root) {
dfs(root);
return maxPath;
}
public int[] dfs(TreeNode root){
if(root == null){
return new int[]{-1, -1};
}
//0表示左树的交叉最大长度,1表示右树的交叉最大长度
int[] ans = new int[2];
int[] left = dfs(root.left);
int[] right = dfs(root.right);
ans[0] = 1 + left[1];
ans[1] = 1 + right[0];
maxPath = Math.max(maxPath, Math.max(ans[0], ans[1]));
return ans;
}
}
128. 最长连续序列
难度困难
因为是未排序,所以最开始没什么思路。看了题解之后发现可以用set来做。因为原数组本来就是无序的集合。先把元素加入到set中,之后再考虑以某个数字作为连续序列开头的情况(也只有这种情况才由可能得到最长的序列)。
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums){
set.add(num);
}
int maxLen = 0;
for(int num : nums){
if(!set.contains(num - 1)){//只考虑从某个数字为开头
int curNum = num;
int curLen = 1;
while(set.contains(curNum + 1)){
curNum++;
curLen++;
}
maxLen = Math.max(maxLen, curLen);
}
}
return maxLen;
}
}
1169. 查询无效交易
难度中等
主要是需要一个内部来来对交易进行初始化及放置。
其实用一个双重循环就能解决,不要把问题想得太过复杂。
class Solution {
public List<String> invalidTransactions(String[] transactions) {
Transaction[] trans = new Transaction[transactions.length];
int index = 0;
for(String tran : transactions){
String[] strings = tran.split(",");
trans[index++] = new Transaction(strings[0],Integer.parseInt(strings[1]),Integer.parseInt(strings[2]),strings[3]);
}
List<String> list = new ArrayList<>();
for(int i = 0;i < trans.length;i++){
if(trans[i].money > 1000)list.add(transactions[i]);
else{
for(int j = 0;j < trans.length;j++){
if(i != j && trans[j].name.equals(trans[i].name) &&
!trans[j].city.equals(trans[i].city) &&
Math.abs(trans[j].time - trans[i].time) <= 60){
list.add(transactions[i]);
break;
}
}
}
}
return list;
}
}
class Transaction{
String name;
Integer time;
Integer money;
String city;
public Transaction(String name, Integer time, Integer money, String city) {
this.name = name;
this.time = time;
this.money = money;
this.city = city;
}
}
7.29
23. 合并K个排序链表
难度困难
想不到一次遍历全部的解法,按照自己的想法写了实现。还是把两个链表相加,直到包全部链表都相加了。但是这样的复杂度可能会偏高。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode head = null;
for(int i = 0;i < lists.length;i++){
head = mergeLists(lists[i], head);
}
return head;
}
public ListNode mergeLists(ListNode l1, ListNode l2){
if(l1 == null){
return l2;
}
if(l2 == null){
return l1;
}
ListNode dummy = new ListNode();
ListNode node = dummy;
while(l1 != null && l2 != null){
int value1 = l1.val;
int value2 = l2.val;
if(value1 < value2){
node.next = new ListNode(value1);
l1 = l1.next;
}else{
node.next = new ListNode(value2);
l2 = l2.next;
}
node = node.next;
}
if(l1 != null){
node.next = l1;
}else if(l2 != null){
node.next = l2;
}
return dummy.next;
}
}
看了题解,发现比较快速的解法是利用优先队列来做的。利用优先队列可以对目前的节点的值进行排序,小的值会被优先弹出。我最开始考虑的使用一个TreeMap来做,但是想了一下不太行。看来对各种数据结构还是不太熟悉。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);//值小的会放在前面,并优先弹出
for (ListNode node: lists) {
if (node != null) {
pq.offer(node);
}
}
ListNode dummyHead = new ListNode(0);
ListNode tail = dummyHead;
while (!pq.isEmpty()) {
ListNode minNode = pq.poll();
tail.next = minNode;
tail = minNode;
if (minNode.next != null) {
pq.offer(minNode.next);
}
}
return dummyHead.next;
}
}
31. 下一个排列
难度中等
这个题最开始想简单了,以为要找到从前往后找到递减序列结束的值。所以实际上并没有那么简单。
看了题解才做出来。主要想法是从后往前遍历,找到递增序列结束的位置。之后再把这个值与其后第一个大于它的值进行交换(从后往前)。最后再翻转后面的数组就能得到下一个最小排列。
public class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i + 1] <= nums[i]) {
i--;
}//从末尾开始,找到不满足递增的下标
if (i >= 0) {//如果有满足条件的索引,如果不满足的话就翻转整个数组
int j = nums.length - 1;
while (j >= 0 && nums[j] <= nums[i]) { // 找到比nums[i]更大的一个数,并交换位置
j--;
}
swap(nums, i, j);
}
//翻转后面的顺序
reverse(nums, i + 1);
}
private void reverse(int[] nums, int start) {
int i = start, j = nums.length - 1;
while (i < j) {
swap(nums, i, j);
i++;
j--;
}
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
33. 搜索旋转排序数组
难度中等
这个题感觉不难,主要还是逻辑没理清楚。
class Solution {
public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1, mid = 0;
while (lo <= hi) {
mid = lo + (hi - lo) / 2;
if (nums[mid] == target) {
return mid;
}
// 先根据 nums[mid] 与 nums[lo] 的关系判断 mid 是在左段还是右段
if (nums[mid] >= nums[lo]) {//前面有序
if (target >= nums[lo] && target < nums[mid]) {//target在不在有序的序列中
hi = mid - 1;
} else {
lo = mid + 1;
}
} else {//前面无序,也就是后面有序
if (target > nums[mid] && target <= nums[hi]) {//target在不在有序的序列中
lo = mid + 1;
} else {
hi = mid - 1;
}
}
}
return -1;
}
}
48. 旋转图像
难度中等
前段时间才做过,但是现在做又有点理不清逻辑了,还是要多做题啊。
j表示偏移量,i表示现在在旋转的层数
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
for(int i = 0;i < n / 2;i++){
for(int j = i;j < n - i - 1;j++){
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - 1 - i][n - j - 1];
matrix[n - 1 - i][n - j - 1]=matrix[j][n - 1 - i];
matrix[j][n - 1 - i]=temp;
}
}
}
}
7.30
343. 整数拆分
难度中等
这个题通过举了几个例子,发现在n大于4的情况下应该要尽可能把数字拆分了拥有更多个3。但是有一个特殊情况,就是当最后是4时,这时不应该再次拆分,而就应该用4来表示。
class Solution {
public int integerBreak(int n) {
if(n == 2){
return 1;
}else if(n == 3){
return 2;
}else if(n == 4){
return 4;
}
int count = n / 3;
int num = n % 3;
if(num == 1 && count > 1){
count--;
num += 3;
}
if(num != 0){
return (int)Math.pow(3, count) * num;
}else{
return (int)Math.pow(3, count);
}
}
}
617. 合并二叉树
难度简单
就是一个简单的递归就可以解决。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1 == null){
return t2;
}
if(t2 == null){
return t1;
}
TreeNode root = new TreeNode(t1.val + t2.val);
root.left = mergeTrees(t1.left, t2.left);
root.right = mergeTrees(t1.right, t2.right);
return root;
}
}
8.1
236. 二叉树的最近公共祖先
难度中等
之前已经做过类似的题目了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q){
return root;
}
TreeNode l = lowestCommonAncestor(root.left, p, q);
TreeNode r = lowestCommonAncestor(root.right, p, q);
if(l != null && r != null){
return root;
}else if(l == null){
return r;
}else{
return l;
}
}
}
283. 移动零
难度简单
我的想法是先记录下0的数量,再把所有的0放在连续的地方,之后把后面的元素赋给0的序列中。最后再把数组后面对应的0的数量的地方置为0。
class Solution {
public void moveZeroes(int[] nums) {
int count = 0;
for(int num : nums){
if(num == 0){
count ++;
}
}
int begin = 0;
int end = 0;
int len = nums.length;
//把0都放在连续的地方
while(begin < len && end < len){
while(begin < len && nums[begin] != 0){
begin++;
}
while(end < len && nums[end] == 0){
end++;
}
if(begin > end){
end++;
continue;
}
if(begin < len && end < len){
swap(nums, begin, end);
begin++;
end++;
}
}
for(int i = begin + count;i < len;i++){
swap(nums, begin, i);
begin++;
}
if(begin + count < len){
for(int i = 1;i <= count;i++){
nums[len - i] = 0;
}
}
}
public void swap(int[] arr, int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
看了题解发现有更简单的做法。我们只需要将所有非0的值都先放到数组的前面,之后再把之后的序列全部置为0就可以了。
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for(int i = 0;i < nums.length;i++){
if(nums[i] != 0){
nums[j++] = nums[i];
}
}
for(int i = j;i < nums.length;i++){
nums[i] = 0;
}
}
}
8.2
58. 最后一个单词的长度
难度简单
先转变成数组,返回最后一个字符串的长度即可。不过需要注意可能会有多个空格相邻的情况。
class Solution {
public int lengthOfLastWord(String s) {
String[] strs = s.split(" ");
for(int i = strs.length - 1;i >= 0; i--){
if(!strs[i].equals("")){
return strs[i].length();
}
}
return 0;
}
}
或者直接从后面开始遍历,先把末尾的空格都略过,再得到最后一个字符串的长度。
class Solution {
public int lengthOfLastWord(String s) {
int i = s.length() - 1;
while(i >= 0 && s.charAt(i) == ' '){
i--;
}
int len = 0;
while(i >= 0 && s.charAt(i) != ' '){
i--;
len++;
}
return len;
}
}
53. 最大子序和
难度简单
已经做过几遍了。动态的思想。
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0;
int maxSum = Integer.MIN_VALUE;
for(int num : nums){
if(sum > 0){
sum += num;
}else{
sum = num;
}
maxSum = Math.max(maxSum, sum);
}
return maxSum;
}
}
25. K 个一组翻转链表
难度困难
nice,自己把这个题做了出来,而且还是1000%的速度,有进步。
其实也不算特别难,只是在反转链表的基础上增加了条件。我的想法是记录下每次反转链表部分的前一个和后一个节点,之后去反转这部分的链表。反转结束后再把这三部分拼接起来。其中需要注意的是遍历时node的更新规则是不一样的,反转时会对链表有影响,所以不能直接node = node.next。在做的时候这个问题还是困扰了挺久的。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head == null || k == 1){
return head;
}
int len = 0;
ListNode node = head;//遍历链表的节点
ListNode reverseHead = head;//每次反转的头部
ListNode h = head;//初始为head,为了防止一次都不会反转的情况
ListNode pre = null;//链表反转结束之后的最后一个节点
ListNode next = null;//记录下遍历时链表的下一个节点
while(len < k && node != null){
len++;
if(len == k){
next = node.next;
ListNode temp = reverseList(reverseHead, k);//反转链表之后的头结点
if(h == head){//更新头结点
h = temp;
}else{//需要把反转的节点拼接起来
pre.next = temp;
}
pre = reverseHead;
reverseHead.next = next;//reverseHead现在已经是反转后的末尾
reverseHead = next;
len = 0;
node = next;
}else{
node = node.next;
}
}
return h;
}
//反转链表
public ListNode reverseList(ListNode head, int k){
ListNode pre = null;//反转用的,是反转的头部
ListNode next = null;
ListNode node = head;
int len = 0;
while(len < k && node != null){
next = node.next;
node.next = pre;
pre = node;
node = next;
len++;
}
return pre;
}
}
29. 两数相除
难度中等
emmm,只会用暴力来做,不过超时了。
看了题解,发现可以用二分的思想来做。主要想法是每次都尽可能多的减去2^n的divisor。
class Solution {
public int divide(int dividend, int divisor) {
if(dividend == Integer.MIN_VALUE && divisor == -1)
return Integer.MAX_VALUE;
boolean k = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
int result = 0;
dividend = -Math.abs(dividend);
divisor = -Math.abs(divisor);
while(dividend <= divisor) {
int temp = divisor;
int c = 1;
while(dividend - temp <= temp) {
temp = temp << 1;
c = c << 1;
}
dividend -= temp;
result += c;
}
return k ? result : -result;
}
}
44. 通配符匹配
难度困难
最开始用了回溯的做法,但是超时了。之后就没有了思路。
看了题解,发现可以用动态规划的方法来做。确实这样做的话会比较简单。
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] dp = new boolean[m + 1][n + 1];//i、j分别表示s的i位置与p的j位置是否匹配
dp[0][0] = true;
for(int i = 1;i <= n;i++){//首先处理p的开头为*的情况,这种情况下不论s为什么都能匹配
if(p.charAt(i - 1) == '*'){
dp[0][i] = true;
}else{
break;
}
}
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?'){
dp[i][j] = dp[i - 1][j - 1];
}else if(p.charAt(j - 1) == '*'){
dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
}
}
}
return dp[m][n];
}
}
98. 验证二叉搜索树
难度中等
二叉搜索树的中序遍历序列应该是一个递增的序列。所以简单的方法就是先中序遍历得到序列,在判断序列是不是递增的。如果递增则满足要求,如果不是,则不是二叉搜索树。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
List<Integer> list = new ArrayList<>();
inorder(root, list);
for(int i = 1;i < list.size();i++){
if(list.get(i) <= list.get(i - 1)){
return false;
}
}
return true;
}
public void inorder(TreeNode root, List<Integer> list){
if(root == null){
return ;
}
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
8.6
415. 字符串相加
难度简单
主要就是位数的相加。
class Solution {
public String addStrings(String num1, String num2) {
if(num1.length() == 0){
return num2;
}
if(num2.length() == 0){
return num1;
}
StringBuilder sb = new StringBuilder();
int carry = 0;
int index1 = num1.length() - 1;
int index2 = num2.length() - 1;
while(index1 >= 0 || index2 >= 0 || carry > 0){
int value1 = index1 >= 0 ? Integer.parseInt(String.valueOf(num1.charAt(index1))) : 0;
int value2 = index2 >= 0 ? Integer.parseInt(String.valueOf(num2.charAt(index2))) : 0;
int sum = value1 + value2 + carry;
carry = sum / 10;
sb.append(sum % 10);
index1--;
index2--;
}
return sb.reverse().toString();
}
}
207. 课程表
难度中等
这个题一看就是深度遍历去找有没有环,但是自己的写法总有问题。先把自己的做法记录下来。
class Solution {
//用图的形式表示,不能有环,如果有环则说明不能完成。没有环则说明可以完成课程表
class Node{
int course;
List<Node> pres = new ArrayList<>();
Node(int course){
this.course = course;
}
}
public boolean canFinish(int numCourses, int[][] prerequisites) {
Map<Integer, Node> map = new HashMap<>();
for(int i = 0;i < prerequisites.length;i++){
int course = prerequisites[i][0];
int pre = prerequisites[i][1];
//先处理前续课程
Node preNode = null;
if(map.containsKey(pre)){
preNode = map.get(pre);
}else{
preNode = new Node(pre);
map.put(pre, preNode);
}
//再处理现在的课程
Node curNode = null;
if(map.containsKey(course)){
curNode = map.get(course);
}else{
curNode = new Node(course);
map.put(course, curNode);
}
curNode.pres.add(preNode);
}
// for(Map.Entry<Integer, Node> entry : map.entrySet()){
// System.out.println(entry.getKey() + ":");
// for(Node pre : entry.getValue().pres){
// System.out.print(pre.course + " ");
// }
// System.out.println();
// System.out.println("-----------------");
// }
//所有的节点都处理过了,现在去判断其中的节点有没有环。
for(int i = 0;i < numCourses;i++){
if(map.containsKey(i)){
if(!dfs(map.get(i), new boolean[numCourses])){
return false;
}
}
}
return true;
}
public boolean dfs(Node node, boolean[] learned){
List<Node> pres = node.pres;
for(int i = 0;i < pres.size();i++){
Node pre = pres.get(i);
if(learned[pre.course]){
return false;
}
learned[pre.course] = true;
if(!dfs(pre, learned)){
return false;
}
}
return true;
}
}
然后去看了题解,发现别人的思路就是清晰。把节点分为3个状态,根据节点的状态来判断有没有存在环。
class Solution {
List<List<Integer>> edges;
int[] visited;
boolean valid = true;
public boolean canFinish(int numCourses, int[][] prerequisites) {
edges = new ArrayList<List<Integer>>();
for (int i = 0; i < numCourses; ++i) {
edges.add(new ArrayList<Integer>());
}
visited = new int[numCourses];
for (int[] info : prerequisites) {
edges.get(info[1]).add(info[0]);
}
for (int i = 0; i < numCourses && valid; ++i) {
if (visited[i] == 0) {//0标识未搜索,1标识搜索中,2标识已经搜索结束
dfs(i);
}
}
return valid;
}
public void dfs(int u) {
visited[u] = 1;
for (int v: edges.get(u)) {
if (visited[v] == 0) {
dfs(v);
if (!valid) {
return;
}
} else if (visited[v] == 1) {
valid = false;
return;
}
}
visited[u] = 2;
}
}
8.7
169. 多数元素
难度简单
最简单的就是哈希表
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>();
for(int num : nums){
if(map.containsKey(num)){
map.put(num, map.get(num) + 1);
}else{
map.put(num, 1);
}
}
int count = nums.length / 2;
for(Map.Entry<Integer, Integer> entry : map.entrySet()){
if(entry.getValue() > count){
return entry.getKey();
}
}
return -1;
}
}
因为一定存在目标值,所以可以先排序,中位数一定是我们想要的结果。不过这样的做法改变了原有数组的顺序。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
}
309. 最佳买卖股票时机含冷冻期
难度中等
股票问题,动态规划问题。这个题最开始觉得有三个状态没错,但是自己在划分的时候错了,所以状态转移方程一直没写出来。参照了题解才做出来。主要还是状态转移要写对。
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if(len == 0){
return 0;
}
int[][] dp = new int[len][3];//0表示持有股票,1表示不持有股票,且处于冷冻期,2表示不持有股票,也不处于冷冻期;
dp[0][0] = -prices[0];
for(int i = 1;i < len;i++){
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]);//这个股票可能是之前就持有的,也可能是今天不在冷冻期当天购买的
dp[i][1] = dp[i - 1][0] + prices[i];//前一天进行了买入,今天处于冷冻的话,就需要卖出之前的股票
dp[i][2] = Math.max(dp[i - 1][1], dp[i - 1][2]);//不持有股票,也不在冷冻期,说明今天没有做任何操作,现在的最大值就是之前的最大钱数。[0]当天买入股票没有意义
}
return Math.max(dp[len - 1][1], dp[len - 1][2]);
}
}
226. 翻转二叉树
难度简单
递归解决
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null){
return root;
}
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
146. LRU缓存机制
难度中等
主要是用linkedList和map来实现的。为什么要用map,就是为了能够在O1的时间内得到对应的value。
class LRUCache {
private LinkedList<Integer> list = new LinkedList<>();
private Map<Integer, Integer> map = new HashMap<>();
private int capacity;
private int curSize = 0;
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
if(map.containsKey(key)){
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
int item = iter.next();
if (item == key) {
iter.remove();
}
}
list.add(key);
return map.get(key);
}else{
return -1;
}
}
public void put(int key, int value) {
if(map.containsKey(key)){
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
int item = iter.next();
if (item == key) {
iter.remove();
}
}
list.add(key);
map.put(key, value);
return ;
}
if(curSize < capacity){
curSize++;
}else{
//满了,需要弹出一个
map.remove(list.removeFirst());
}
map.put(key, value);
list.add(key);
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
238. 除自身以外数组的乘积
难度中等
主要思想就是用左右相乘数组。我在做的时候nums的索引用错了,所以花了好些时间去找问题。
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
if(n == 0){
return new int[0];
}
int[] leftArr = new int[n];
int[] rightArr = new int[n];
leftArr[0] = 1;
rightArr[n - 1] = 1;
for(int i = 1;i < n;i++){
leftArr[i] = nums[i - 1] * leftArr[i - 1];
}
for(int i = n - 2;i >= 0;i--){
rightArr[i] = nums[i + 1] * rightArr[i + 1];
}
int[] ans = new int[n];
for(int i = 0;i < n;i++){
// System.out.println(i + ":" + leftArr[i] + "--" + rightArr[i]);
ans[i] = leftArr[i] * rightArr[i];
}
return ans;
}
}
543. 二叉树的直径
难度简单
主要是计算深度,用一个全局变量来维护得到的最大直径。
class Solution {
int ans;
public int diameterOfBinaryTree(TreeNode root) {
ans = 1;
depth(root);
return ans - 1;
}
public int depth(TreeNode node) {
if (node == null)
return 0; // 访问到空节点了,返回0
int L = depth(node.left); // 左儿子为根的子树的深度
int R = depth(node.right); // 右儿子为根的子树的深度
ans = Math.max(ans, L + R + 1); // 计算d_node即L+R+1 并更新ans
return Math.max(L, R) + 1; // 返回该节点为根的子树的深度
}
}