当前位置: 首页 > news >正文

管理系统和网站哪个好做/品牌推广内容

管理系统和网站哪个好做,品牌推广内容,深圳做app网站建设,表白网页生成助手目录 数组 1. LCR 121. 寻找目标值 - 二维数组 2. LCR 120. 寻找文件副本 3. LCR 128. 库存管理 I 4. LCR 131. 砍竹子 I 5. LCR 132. 砍竹子 II 6. LCR 135. 报数 7. LCR 139. 训练计划 I 8. LCR 158. 库存管理 II 9. LCR 159. 库存管理 III 10. LCR 160. 数据流中…

目录

数组

1. LCR 121. 寻找目标值 - 二维数组

2. LCR 120. 寻找文件副本

3. LCR 128. 库存管理 I

4. LCR 131. 砍竹子 I

5. LCR 132. 砍竹子 II

6. LCR 135. 报数

7. LCR 139. 训练计划 I

8. LCR 158. 库存管理 II

9. LCR 159. 库存管理 III

10. LCR 160. 数据流中的中位数

11. LCR 164. 破解闯关密码

12. LCR 168. 丑数

13. LCR 170. 交易逆序对的总数

14. LCR 172. 统计目标成绩的出现次数

15. LCR 173. 点名

16. LCR 179. 查找总价格为目标值的两个商品

17. LCR 180. 文件组合

18. LCR 183. 望远镜中最高的海拔

19. LCR 186. 文物朝代判断

20. LCR 189. 设计机械累加器

21. LCR 191. 按规则计算统计结果

字符串

22. LCR 122. 路径加密

23. LCR 138. 有效数字

24. LCR 157. 套餐内商品的排列顺序

25. LCR 167. 招式拆解 I

26. LCR 169. 招式拆解 II

27. LCR 181. 字符串中的单词反转

28. LCR 182. 动态口令

29. LCR 192. 把字符串转换成整数 (atoi)

链表

30. LCR 123. 图书整理 I

31. LCR 136. 删除链表的节点

32. LCR 140. 训练计划 II

33. LCR 141. 训练计划 III

34. LCR 142. 训练计划 IV

35. LCR 171. 训练计划 V

36. LCR 154. 复杂链表的复制

栈和队列

37. LCR 147. 最小栈

38. LCR 125. 图书整理 II

39. LCR 184. 设计自助结算系统

40. LCR 148. 验证图书取出顺序

41. LCR 124. 推理二叉树

42. LCR 143. 子结构判断

43. LCR 144. 翻转二叉树

44. LCR 145. 判断对称二叉树

45. LCR 149. 彩灯装饰记录 I

46. LCR 150. 彩灯装饰记录 II

47. LCR 151. 彩灯装饰记录 III

48. LCR 152. 验证二叉搜索树的后序遍历序列

49. LCR 153. 二叉树中和为目标值的路径

50. LCR 155. 将二叉搜索树转化为排序的双向链表

51. LCR 156. 序列化与反序列化二叉树

52. LCR 174. 寻找二叉搜索树中的目标节点

53. LCR 175. 计算二叉树的深度

54. LCR 176. 判断是否为平衡二叉树

55. LCR 193. 二叉搜索树的最近公共祖先

56. LCR 194. 二叉树的最近公共祖先

位运算

57. LCR 133. 位 1 的个数

58. LCR 134. Pow(x, n)

59. LCR 177. 撞色搭配

60. LCR 178. 训练计划 VI

61. LCR 190. 加密运算

动态规划

62. LCR 126. 斐波那契数

63. LCR 127. 跳跃训练

64. LCR 137. 模糊搜索验证

65. LCR 161. 连续天数的最高销售额

66. LCR 165. 解密数字

67. LCR 166. 珠宝的最高价值

68. LCR 185. 统计结果概率

69. LCR 187. 破冰游戏

70. LCR 129. 字母迷宫

71. LCR 130. 衣橱整理​编辑

72. LCR 146. 螺旋遍历二维数组

贪心算法

73. LCR 188. 买卖芯片的最佳时机

找规律

74. LCR 162. 数字 1 的个数

75. LCR 163. 找到第 k 位数字


数组

1. LCR 121. 寻找目标值 - 二维数组

就是根据矩阵特性,来查找矩阵值,每行从左到右是递增的,每一列从上到下是递增的。

我们可以从数组的右上角 arr[i][j] 开始,如果 target 大于arr[i][j],那就 i++ 往后走,如果比它小,那就 j-- 往前走,如果相等返回 true,数组越界了也没找到该值就返回 false。

代码实现:

class Solution {public boolean findTargetIn2DPlants(int[][] plants, int target) {// 注意数组没有值的情况if (plants.length == 0) return false;// 找到右上角的值int i = 0;int j = plants[0].length - 1;while (i >= 0 && i < plants.length && j >= 0 && j < plants[0].length) {if (plants[i][j] > target) {j--;} else if (plants[i][j] < target) {i++;} else {return true;}}return false;}
}

2. LCR 120. 寻找文件副本

寻找重复出现数字,直接两层遍历暴力破解即可。

或者直接调用库函数给数组排下序,然后再相邻两两比较,相同就返回。

或者用 set 来做,遍历数组,如果元素在 set 中存在,则返回元素,如果不存在,就把元素添加进 set 里。

代码实现:

class Solution {public int findRepeatDocument(int[] documents) {for (int i = 0; i < documents.length - 1; i++) {for (int j = i + 1; j < documents.length; j++) {if (documents[i] == documents[j]) {return documents[i];}}}return -1;}
}class Solution {public int findRepeatDocument(int[] documents) {Arrays.sort(documents);for (int i = 0; i < documents.length - 1; i++) {if (documents[i] == documents[i + 1]) {return documents[i];}}return -1;}
}class Solution {public int findRepeatDocument(int[] documents) {Set<Integer> set = new HashSet<>();for (int i = 0; i < documents.length; i++) {int x = documents[i];if (set.contains(x)) {return x;} else {set.add(x);}}return -1;}
}

3. LCR 128. 库存管理 I

这个简单,直接遍历数组找最小元素即可。

也可以用二分查找,因为是部分区间是升序的,就可以利用二分查找来完成。

以 s[right] 为参照物, 用中间值 s[mid] 与 s[right] 比较,如果 s[mid] > s[right] ,如例 1 ,则说明最小元素在 mid + 1, right 区间,如果小于,则说明最小元素在 left, mid 区间,如果相等,就无法以判断 right 来判断最小元素在哪里,所以 right-- 往前找另一个参照物。最后 left 与 right 重合时就是最小值的下标。

代码实现:

class Solution {public int stockManagement(int[] stock) {int min = Integer.MAX_VALUE;for (int i = 0; i < stock.length; i++) {if (stock[i] < min) {min = stock[i];}}return min;}
}// 二分查找
class Solution {public int stockManagement(int[] stock) {int left = 0;int right = stock.length - 1;while (left < right) {int mid = (left + right) / 2;if (stock[mid] > stock[right]) {left = mid + 1;} else if (stock[mid] == stock[right]) {right--;} else {right = mid;}}return stock[right];}
}

4. LCR 131. 砍竹子 I

可以用动态规划来做,dp[i] 就是长度为 i 的竹子拆分两段或以上的最大乘积

i 拆分分两种情况,第一,只拆分成 2 段,j 和 i - j。 乘积就是 j * (i - j)

第二,拆分成两段以上,j , i - j 还继续拆分,乘积就是 j * dp[i - j]

所以 dp[i] 就是上面两种情况的结果集合中最大值。

初始化:因为 i = 0 和 i = 1 时不能拆分,所以 dp[0] = dp[1] = 0。

最后返回 dp[bl] 即可。

代码实现:

class Solution {public int cuttingBamboo(int bamboo_len) {// dp[i] 是长度为 i 的竹子拆分为两段或以上的最大乘积int[] dp = new int[bamboo_len + 1];// 初始化 dp[0] = dp[1] = 0dp[0] = 0;dp[1] = 0;for (int i = 2; i <= bamboo_len; i++) {// 分两种情况,一种是竹子 i 只拆分成两个数字 3 = 2 + 1// 分别是 j 和 i - j,另一种是 j,和 i - j 继续拆分成更细的 3 = 1 + 1 + 1// 所以需要 j 从 i - 1 开始遍历,j 》= 1,然后求以上结果集合中的最大的那一个for (int j = i - 1; j >= 1; j--) {int max = Math.max(j * (i - j), j * dp[i - j]);dp[i] = Math.max(dp[i], max);}}return dp[bamboo_len];}
}

5. LCR 132. 砍竹子 II

因为范围变大了,所以就不能用动态规划了。

看题解大佬的思路是将绳子长度尽可能分为多个 3,这样乘积才最大。

所以当 n < 4 的时候,返回 n - 1,当 n 等于 4 的时候,返回 4,当 n > 4 的时候,就要切割成 3 的小端,只要 n > 4,就进行切割,然后将切割出来的 3 累乘,然后取模。

代码实现:

class Solution {public int cuttingBamboo(int n) {if (n < 4) {return n - 1;} else if (n == 4) {return n;} else {long ans = 1;while (n > 4) {ans *= 3;ans %= 1000000007;n -= 3;}return (int) (ans * n % 1000000007);}}
}

6. LCR 135. 报数

就是算出一共有几个数字,然后数组赋值即可。

第二种方法就是全排列,参考大佬的解答,假如数字特别大,就无法用整型来存储数据了,那此时就可以用字符串来存储数据,要生成从 1 到 10^n - 1 的数,我们可以看作是数字 0~9 的排列问题,要循环生成 n 位数,首先是生成第一位数字,第一位一定是 1 ~ 9,然后再递归生成剩下的数字,从 0 ~ 9 中取值,

代码实现:

class Solution {public int[] countNumbers(int cnt) {int len = (int) Math.pow(10, cnt);int[] arr = new int[len - 1];for (int i = 0; i < arr.length; i++) {arr[i] = i + 1;}return arr;}
}// 全排列
class Solution {int count = 0;int ret[];public int[] countNumbers(int cnt) {int len = (int) Math.pow(10, cnt) - 1;ret = new int[len];// i 表示要生成 i 位数for (int i = 1; i <= cnt; i++) {// 首先生成第一位for (char first = '1'; first <= '9'; first++) {// 创建个字符数组存储生成的数字char[] num = new char[i];num[0] = first;// 然后递归生成剩下的数字dfs(1, num, i);}}return ret;}// digit 表示要生成 digit 位数public void dfs(int index, char[] num, int digit) {if (index == digit) {// 接下来要生成 index 下标的数字,// 此时说明已经生成了 digit 位数,将其存入数组中并返回即可ret[count++] = Integer.valueOf(String.valueOf(num));return;}// 生成范围是 0 ~ 9for (char i = '0'; i <= '9'; i++) {num[index] = i;// 继续生成剩下的数字dfs(index + 1, num, digit);}}
}

7. LCR 139. 训练计划 I

这个简单,用双指针就行,left 从 0 下标开始找偶数,right 从最后一个位置开始找奇数,然后交换 left 和 right 下标的值,然后 left 和 right 再继续往后找下一组,直到 left 和 right 相遇。

代码实现:

class Solution {public int[] trainingPlan(int[] actions) {// 这个简单int left = 0;int right = actions.length - 1;while (left < right) {// left 往后走找偶数while (left < right && actions[left] % 2 == 1) {left++;}// right 往前找奇数while (left < right && actions[right] % 2 == 0) {right--;}// 此时 left 一定是偶数, right 一定是奇数,交换int tmp = actions[left];actions[left] = actions[right];actions[right] = tmp;}return actions;}
}

8. LCR 158. 库存管理 II

这个也简单,将数组排序,排完序后,下标为 arr.length / 2 的元素就一定是出现次数超过一半的数字。还有另一种方法,叫做摩尔投票法,简单来说就是假设该数是众数 x ,那么遇到 x 就 count++,不是 x 就 count--,如果此时 count 为 0 了,那么说明 x 一定不是众数,因为众数的出现次数大于数组的一半,所以遍历完数组,最后 count 应该是大于 0 的。 

代码实现:

class Solution {public int inventoryManagement(int[] stock) {Arrays.sort(stock);return stock[stock.length / 2];}
}// 投票法
class Solution {public int inventoryManagement(int[] stock) {int count = 1;int x = stock[0];for (int i = 1; i < stock.length; i++) {if (count == 0) {// 当票数为 0 时,则说明此时 x 不是众数// 就需要重新假设当前数字为众数x = stock[i];}if (x == stock[i]) {// 数字相同,则票数++count++;} else {// 数字不同,则票数--count--;}}return x;}
}

9. LCR 159. 库存管理 III

这个简单,就是先排序,然后返回范围从 0 到 cnt - 1 下标的数组即可。

也可以用优先级队列来做,求前 k 大的元素,建立小根堆,然后遍历数组,前 k 个入队,从 第 k+1 个元素开始与堆顶元素比较,如果 k+1 元素大于堆顶元素,那么堆顶元素出队,第 k+1 元素入队,遍历完数组后,堆顶元素就是第 k 大的元素。求前 k 小元素,就建立大根堆,与上面思路类似。

代码实现:

class Solution {public int[] inventoryManagement(int[] stock, int cnt) {Arrays.sort(stock);return Arrays.copyOfRange(stock, 0, cnt);}
}// 利用优先级队列解决 top-k 问题
class Solution {public int[] inventoryManagement(int[] stock, int cnt) {if (stock == null || stock.length == 0 || cnt <= 0) return new int[0];// 或者利用大根堆来做,就是 tok-k 问题PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {return o2 - o1;}});for (int i = 0; i < stock.length; i++) {if (i < cnt) {queue.offer(stock[i]);} else {int top = queue.peek();if (top > stock[i]) {queue.poll();queue.offer(stock[i]);}}}// 最后队列里就是前 cnt 个小的元素int[] ret = new int[cnt];for (int i = cnt - 1; i >= 0; i--) {ret[i] = queue.poll();}return ret;}
}

10. LCR 160. 数据流中的中位数

如图,题目让你找有序数组中的中位数,那就是先定义一个数组 arr 用来存放数据,然后再定义 usedSize 记录数组大小,然后写新增元素方法,那就是先判断数组满没满,满了就扩容,然后再新增元素,写寻找中位数时,可以先排序这个数组,使用直接插入排序即可,然后再来找到中位数。

看了大佬的题解,发现可以用两个优先级队列来做,队列 A 存储较大的一半数字(小根堆),队列 B 存储较小的一半数字(大根堆)。

新增元素 num 时,当 A 的元素个数等于 B 的元素个数时,需要往 A 队列增加元素,先把 num 添加进 B 队列中,然后再让 B 队列的堆顶元素添加进 A 队列中。当 A 的元素个数不等于 B 的元素个数时,需要往 B 添加元素,将 num 放入 A 队列中,然后再将 A 队列的堆顶元素放入 B 队列中。

查找中位数,如果两个队列的元素个数不相等,那就返回 A 队列的堆顶元素,如果元素个数相等,那就返回两队列的堆顶元素的和除以 2.0。

代码实现:

class MedianFinder {/*** initialize your data structure here.*/int usedSize = 0;int[] arr;public MedianFinder() {arr = new int[10];}public void addNum(int num) {// 扩容if (usedSize == arr.length) {this.arr = Arrays.copyOf(arr, arr.length * 2);}arr[usedSize] = num;usedSize++;}public double findMedian() {if (usedSize == 0) {return -1.0;}// 直接插入排序for (int i = 1; i < usedSize; i++) {int j = i - 1;int tmp = arr[i];for (; j >= 0; j--) {if (arr[j] > tmp) {arr[j + 1] = arr[j];} else {break;}}arr[j + 1] = tmp;}if (usedSize % 2 == 1) {return (double) arr[usedSize / 2];} else {double sum = arr[usedSize / 2] + arr[usedSize / 2 - 1];return sum / 2;}}
}// 利用两个优先级队列来解决
class MedianFinder {PriorityQueue<Integer> A, B;/*** initialize your data structure here.*/public MedianFinder() {// A 是小根堆,B 是大根堆A = new PriorityQueue<Integer>();B = new PriorityQueue<Integer>(new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {return o2 - o1;}});}public void addNum(int num) {if (A.size() == B.size()) {// 则需要往 A 队列中添加元素B.offer(num);A.offer(B.poll());} else {// 需要往 B 队列添加元素A.offer(num);B.offer(A.poll());}}public double findMedian() {if (A.size() == B.size()) {return (A.peek() + B.peek()) / 2.0;} else {return A.peek();}}
}

11. LCR 164. 破解闯关密码

这道题本质上就是排序问题,字符串之间的排序,可以用冒泡排序来写。

比如示例 2: 

0,3,30,34,5,9

0 和 3 不需要交换,因为 03 <= 30 ,         0,3,30,34,5,9

3 和 30 需要交换,因为 330 > 303,          0,30,3,34,5,9

3 和 34 不需要交换,因为 334 <= 343,    0,30,3,34,5,9

34 和 5 不需要交换,因为 345 <= 543,    0,30,3,34,5,9

5 和 9 不需要交换,因为 59 <= 95,          0,30,3,34,5,9

那假设数组后面还有个 1 的话:0,3,30,34,5,9,1

那么 9 和 1 需要交换,0,30,3,34,5,1,9,而 1 很明显应该要在 0 之后,所以排序需要多来几趟,就可以用冒泡排序,根据相邻两个数字的拼接顺序的后的大小,来判断两个数字要不要交换。排完序后就再次遍历数组,拼接数组中元素,然后返回字符串即可。

代码实现:

class Solution {public String crackPassword(int[] password) {// 冒泡排序for (int i = 0; i < password.length - 1; i++) {boolean flg = true;for (int j = 0; j < password.length - 1 - i; j++) {// 8 和 7 --> 87 和 78  , 87 > 78, 则需要交换 String s1 = password[j] + "" + password[j + 1];String s2 = password[j + 1] + "" + password[j];if (s1.compareTo(s2) > 0) {int tmp = password[j];password[j] = password[j + 1];password[j + 1] = tmp;flg = false;}}if (flg) break;}// 最后遍历数组,拼接字符串即可StringBuilder s = new StringBuilder();for (int i = 0; i < password.length; i++) {s.append(password[i]);}return s.toString();}
}// 解法二:重写排序方法
class Solution {public String crackPassword(int[] password) {List<String> arr = new ArrayList<>();for (int num : password) {arr.add(String.valueOf(num));}arr.sort(new Comparator<String>() {public int compare(String s1, String s2) {return (s1 + s2).compareTo(s2 + s1);}});StringBuilder ans = new StringBuilder();for (String x : arr) {ans.append(x);}return ans.toString();}
}

12. LCR 168. 丑数

根据题目可以发现,第 n 个丑数其实就是通过前面的丑数 * 2,或者丑数 * 3,或者丑数 * 5,并且按照升序排列得到的,所以这道题可以用动态规划来做,dp[i] 就表示第 i 个丑数的值。

我们可以先定义三个指针,p2,p3,p5。

p2 表示 dp 数组中还没使用过乘 2 机会的,数字的下标(p2 前面的下标对应的数字都使用过 * 2 得到了一个丑数)。p3 和 p5 同理。所以在一开始,p2 和 p3 和 p5 都指向初始位置 1,dp[1] = 1。

然后 dp[i] 就等于 还没使用过乘 2 机会的数字 * 2,还没使用过乘 3 机会的数字 * 3,还没使用过乘 5 机会的数字 * 5,中的最小值,然后判断使用这三个指针是否得到了 dp[i],如果是,那么对应的下标往后走。最后返回 dp[n] 即可。

代码实现:

class Solution {public int nthUglyNumber(int n) {int[] dp = new int[n + 1];dp[1] = 1;// p2 表示 dp 数组中还没使用乘 2 机会的第一个数字所对应的下标int p2 = 1, p3 = 1, p5 = 1;for (int i = 2; i <= n; i++) {int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;// dp[i] 就是这三个数字中最小的那个dp[i] = Math.min(num2, num3);dp[i] = Math.min(dp[i], num5);if (dp[i] == num2) {// 当前下标的数字已经使用过乘 2 机会了,那么 p2 需要往后走p2++;}if (dp[i] == num3) {p3++;}if (dp[i] == num5) {p5++;}}return dp[n];}
}

13. LCR 170. 交易逆序对的总数

第一眼,看上就就是两次遍历,前一个大于后一个,那就 count++,最后返回 count,但是超时了。看题解发现能用归并排序来做,在合并数组的时候,如果 arr[i] (i >= left && i <= mid)大于 arr[j] (j > mid && j <= right) ,则说明至少有 mid - i + 1 个逆序对,用 count 来记录,最后返回 count 即可。

代码实现:

class Solution {int count = 0;public int reversePairs(int[] record) {// 可以用归并排序来做mergeSort(record, 0, record.length - 1);return count;}public void mergeSort(int[] arr, int left, int right) {// 只有一个元素,不用排序if (left >= right) return;// 二分int mid = (left + right) / 2;// 分割左边mergeSort(arr, left, mid);// 分割右边mergeSort(arr, mid + 1, right);// 合并merge(arr, left, mid, right);}public void merge(int[] arr, int left, int mid, int right) {int[] tmpArr = new int[right - left + 1];// 合并有序数组int i = left, j = mid + 1, k = 0;while (i <= mid && j <= right) {if (arr[i] <= arr[j]) {tmpArr[k++] = arr[i++];} else {// 因为 arr[i] > arr[j]// 所以 left 到 mid 区间的所有元素都比 arr[j] 大// [1,3,5,9]  [2,6,7]// 3 > 2, 所以 3,5,9 也大于 2count += (mid - i + 1);tmpArr[k++] = arr[j++];}}while (i <= mid) {tmpArr[k++] = arr[i++];}while (j <= right) {tmpArr[k++] = arr[j++];}// 拷贝回原数组for (i = left; i <= right; i++) {arr[i] = tmpArr[i - left];}}
}

14. LCR 172. 统计目标成绩的出现次数

这个很简单,直接遍历数组,看看当前元素与 target 是否相同,相同就 count++,最后返回 count 即可。还可以用二分查找来做,先查找出数组最前面的 target 的下标,然后再找出最后面 target 的下标,然后返回下标差 + 1 即可。

代码实现:

class Solution {public int countTarget(int[] scores, int target) {int count = 0;for (int i = 0; i < scores.length; i++) {if (scores[i] == target) {count++;}}return count;}
}// 二分查找
class Solution {public int countTarget(int[] scores, int target) {if (scores == null || scores.length == 0) return 0;// 通过二分查找找出 target 的左边界int left = 0, right = scores.length - 1;while (left < right) {int mid = (left + right) / 2;if (scores[mid] >= target) {right = mid;} else {left = mid + 1;}}// 如果没找到,说明数组没有 targetif (scores[left] != target) return 0;int l = left;// 通过二分查找找出 target 的右边界left = 0;right = scores.length - 1;while (left < right) {int mid = (left + right + 1) / 2;if (scores[mid] <= target) {left = mid;} else {right = mid - 1;}}return right - l + 1;}
}

15. LCR 173. 点名

这个简单,可以把 n 位同学的学号加起来得到 sum (从 1 加到 n),然后再遍历数组,用 sum 减去数组的和就能得到缺席的同学学号。

也可以用哈希表的方法来写,记录数组中每个元素的出现次数,然后遍历哈希表,第一次遇到出现次数为 0 的就是缺失的数字。

也可以看题能得知,数组下标与数组学号是相同的,如果不相同,那么数组下标就是缺失的数字。

也可以用二分查找,缺失的元素在数组的右区间,如果 mid == arr[mid] ,则说明左边不存在缺失元素,所以会来到 [mid + 1, right] 区间来寻找缺失元素。如果不相等,则说明缺失元素很可能就是 mid 本身,所以 right = mid

代码实现:

class Solution {public int takeAttendance(int[] records) {int sum = 0;for (int i = 0; i <= records.length; i++) {sum += i;}for (int i = 0; i < records.length; i++) {sum -= records[i];}return sum;}
}// 哈希表
class Solution {public int takeAttendance(int[] records) {int[] hash = new int[records.length + 1];for (int i = 0; i < records.length; i++) {hash[records[i]]++;}for (int i = 0; i < hash.length; i++) {if (hash[i] == 0) return i;}return 0;}
}class Solution {public int takeAttendance(int[] records) {for (int i = 0; i < records.length; i++) {if (i != records[i]) return i;}return records[records.length - 1] + 1;}
}// 二分查找
class Solution {public int takeAttendance(int[] records) {int left = 0, right = records.length - 1;while (left < right) {int mid = left + (right - left) / 2;if (mid == records[mid]) {// 去右边找,不见的元素在数组右边left = mid + 1;} else {right = mid;}}// 0 1 2 3 4if (records[left] == left) return left + 1;return left;}
}

16. LCR 179. 查找总价格为目标值的两个商品

第一眼就是直接用两次遍历完成,但是发现超时了,可以用双指针来写,定义 left 指向数组最左边,right 指向数组最右边,数组递增,如果 arr[left] + arr[right] > target,说明从arr[left] 与 right 往后的值相加得到的结果还是大于 target,所以此时 right 应该往前走。如果 arr[left] + arr[right] < target,说明 arr[left] 太小了,所以应该 left++ 往后走,当 arr[left] + arr[right] == target 时,直接返回即可。

代码实现:

class Solution {public int[] twoSum(int[] price, int target) {int left = 0, right = price.length - 1;while (left < right) {if (price[left] + price[right] > target) {right--;} else if (price[left] + price[right] < target) {left++;} else {return new int[]{price[left], price[right]};}}return new int[]{0, 0};}
}

17. LCR 180. 文件组合

直接暴力枚举,用两层 for 循环搞定。 

还可以用滑动窗口来做,大致思路就是进窗口,判断,出窗口。

代码实现:

class Solution {public int[][] fileCombination(int target) {ArrayList<int[]> ret = new ArrayList<>();for (int i = 1; i < target; i++) {int sum = i;for (int j = i + 1; j < target; j++) {if (sum == target) {int[] arr = new int[j - i];for (int k = i; k < j; k++) {arr[k - i] = k;}ret.add(arr);break;} else if (sum > target) {break;} else {sum += j;}}}return ret.toArray(new int[ret.size()][]);}
}class Solution {public int[][] fileCombination(int target) {ArrayList<int[]> ret = new ArrayList<>();int left = 1, right = 1;int sum = 0;while (left <= target / 2) {// 说明此时值太小,需要 right 往后挪动while (right < target && sum < target) {sum += right;right++;}if (sum == target) {// 记录结果int[] arr = new int[right - left];for (int i = left; i < right; i++) {arr[i - left] = i;}// 此时说明 right 再往后走,sum 也一定大于 target,// 则需要寻找下一组 sum,那么 left 就需要往后走 ret.add(arr);sum -= left;left++;} else if (sum > target) {// 此时值太大,需要减去一些值,就可以减去 leftsum -= left;left++;}}return ret.toArray(new int[ret.size()][]);}
}

18. LCR 183. 望远镜中最高的海拔

如图,题目明示你用滑动窗口,那这道题就可以用滑动窗口来做。

代码实现:

class Solution {public int[] maxAltitude(int[] heights, int limit) {// 如果数组没有元素,那么返回的数组也不能有元素if (heights.length == 0) return new int[0];// left 为窗口起点,right 为窗口终点int left = 0, right = 0;// count 为当前窗口大小int count = 0;// 记录返回值,k 为 ret 当前存放元素个数int[] ret = new int[heights.length - limit + 1];int k = 0;while (left <= heights.length - limit) {if (count < limit) {// 没到窗口大小,那就入元素right++;count++;} else if (count == limit) {// 从窗口起点到终点找最大值int max = Integer.MIN_VALUE;for (int i = left; i < right; i++) {max = Math.max(max, heights[i]);}ret[k++] = max;// 出窗口left++;count--;} else {// 超过窗口容量,出窗口left++;count--;}}return ret;}
}

19. LCR 186. 文物朝代判断

问你数组的数字是否连续,0 可以当作万能牌,问你 5 张牌能不能组成顺子。

看到这我第一想法就是排序,然后遍历数组,看看数组是否是连续的,如果不是,那就记录差了多少个数字,然后如果万能牌 0 的个数大于等于差的数字个数,则说明数组是连续的,但是还得注意,如果有相同牌,并且相同牌不是 0 的话,则说明数组不是连续的。

看大佬的题解,发现能直接通过找数组最大值和最小值(除 0 外),然后 max - min < 5 则说明连续,那这样就好办了,可以用 set 来判重,遍历数组找最大最小值,然后判断即可。

代码实现:

class Solution {public boolean checkDynasty(int[] places) {// 先排序,然后遍历数组Arrays.sort(places);int count = 0;int sum = 0;for (int i = 0; i < places.length - 1; i++) {if (places[i] == 0) {count++;} else {// 不能有相同牌,有相同牌就不是顺子了if (places[i] == places[i + 1]) return false;// 0,0,6,7,9if (places[i] + 1 != places[i + 1]) {sum += places[i + 1] - 1 - places[i];}}}if (count >= sum) return true;else return false;}
}// set 去重
class Solution {public boolean checkDynasty(int[] places) {Set<Integer> set = new HashSet<>();int min = 14;int max = 0;for (int x : places) {if (x == 0) continue;// 重复牌if (set.contains(x)) {return false;}max = Math.max(x, max);min = Math.min(x, min);set.add(x);}return max - min < 5;}
}

20. LCR 189. 设计机械累加器

我们可以利用短路逻辑,用递归来写,递归出口就是当 target = 1 时,那么我们可以利用短路逻辑与,当 target > 1 && (写要执行的代码),最后再将后面部分改成值恒为真的布尔表达式,最后再返回即可。

代码实现:

class Solution {public int mechanicalAccumulator(int target) {// 用递归,可以利用短路逻辑来写// 如果 target <= 1,则递归停止,否则返回就相加boolean flg = target > 1 && (target += mechanicalAccumulator(target - 1)) > 0;return target;}
}

21. LCR 191. 按规则计算统计结果

这道题不算难,让你求 arrB[i] 为数组 arrA 中除了 arrA[i] 外所有元素的乘积,只需要把 arrA 数组遍历一遍,求出除了 0 外所有元素的乘积 mul,并记录 arrA 中 0 的个数,然后用 mul / arrA[i] 就能得到对应的 arrB[i],然后返回 arrB 即可。

但是有个毒点,那就是要考虑 arrA 中含有元素 0 的情况,但是这个 0 也要分情况讨论:

如果 0 只有一个,那么其他元素相乘就都是 0,而 0 对应的元素既是其他元素的乘积。

如果 0 有两个及以上,那么返回的数组 arrB 的所有元素就都是 0 了。

根据以上思路,代码就很好写啦。

还有另一种方法,看题解知道的可以创建个数组 left 和 right,left[i] 表示 arrA[i] 以前的元素乘积(不包括 arrA[i]),right[i] 表示 arrA[i] 以后的元素乘积(不包括 arrA[i]),这样 arrB[i] = left[i] * right[i]。

代码实现:

class Solution {public int[] statisticalResult(int[] arrayA) {int mul = 1;// 记录数组中 0 的个数int count = 0;int[] arrB = new int[arrayA.length];// 求出数组每个元素的乘积(除 0 外)for (int i = 0; i < arrayA.length; i++) {if (arrayA[i] == 0) {count++;continue;}mul *= arrayA[i];}if (count >= 2) {// 说明数组中有两个及以上的 0 ,则值一定全是 0return new int[arrayA.length];}for (int i = 0; i < arrB.length; i++) {if (count > 0) {// 此时说明数组中含有一个 0,则除 0 外所有数组都是 0if (count == 1) {if (arrayA[i] != 0) {arrB[i] = 0;} else {arrB[i] = mul;}}} else {// 数组中没 0,正常执行arrB[i] = mul / arrayA[i];}}return arrB;}
}class Solution {public int[] statisticalResult(int[] arrayA) {// 边界情况if (arrayA == null || arrayA.length == 0) return new int[0];int[] left = new int[arrayA.length];left[0] = 1;// 遍历数组初始化 left 的值for (int i = 1; i < arrayA.length; i++) {left[i] = left[i - 1] * arrayA[i - 1];}// 记录右边的元素乘积int right = 1;for (int i = left.length - 1; i >= 0; i--) {left[i] *= right;right *= arrayA[i];}return left;}
}

字符串

22. LCR 122. 路径加密

这个很简单,遍历判断即可然后用 StringBuilder 即可。

代码实现:

class Solution {public String pathEncryption(String path) {StringBuilder str = new StringBuilder();for (int i = 0; i < path.length(); i++) {char ch = path.charAt(i);if (ch != '.') {str.append(ch);} else {str.append(' ');}}return str.toString();}
}

23. LCR 138. 有效数字

一种比较简单的做法,就是判断该字符串不是有效数字的情况,严格按照题目规定的顺序来判断字符串:按照 空格,(正负号),数字,(点),数字,(eE,数字),空格

定义四个 flg 来判断字符串中是否有数字,E/e,正负号,点。

先从 0 下标开始遍历字符串,一直跳过空格。

从非空格的地方开始判断,如果是数字,那就将数字 flg 置为 true,然后跳过这一连续的数字,然后判断下标是否已经遍历完字符串,如果是,就返回 true。

如果当前字符是 E/e,如果已经出现过 E/e 之前没有出现过数字,则返回 false,否则将 E/e flg 置为 true,再将其他三个 flg 置为 false,往 E 之后重新开始找数字。

如果当前字符是正负号,如果已经出现过符号,数字,点,就返回 false,否则将 符号 flg 置为 true。

如果当前字符是空格,则说明下标已经遍历到字符串末尾的空格,或者空格被字符之间夹起来了,则退出循环,单独判断。

如果是上述以外的字符,就返回 false。

出了循环,就处理末尾空格的情况,一直跳过空格,如果 下标为字符串长度并且数字 flg 是 true,则返回 true,否则返回 false

代码实现:

class Solution {public boolean validNumber(String s) {// 是否有数字,E,正负号,点boolean hasNum = false;boolean hasE = false;boolean hasSign = false;boolean hasDot = false;// 先跳过开头的空格int index = 0, len = s.length();while (index < len && s.charAt(index) == ' ') {index++;}// 从非空格的字符开始判断// 顺序严格按照 空格,正负号,数字,(点),数字,eE,数字 空格while (index < len) {if (isNum(s.charAt(index))) {hasNum = true;// 如果是数字while (index < len && isNum(s.charAt(index))) {index++;}// 说明字符串全是数字if (index == len) return true;}// 到这里就字符就一定是非数字的char c = s.charAt(index);if (c == 'e' || c == 'E') {// 如果出现多个 E,或者之前没有出现过数字if (hasE || !hasNum) {return false;}hasE = true;// 将其他三个 flg 置为 false,继续从 E 往后找新的数字hasNum = false;hasSign = false;hasDot = false;} else if (c == '+' || c == '-') {// 如果之前出现过符号或者数字或者'.',则返回 falseif (hasSign || hasNum || hasDot) {return false;}hasSign = true;} else if (c == '.') {// 如果之前出现过点或者 eEif (hasDot || hasE) {return false;}hasDot = true;} else if (c == ' ') {// 说明此时可能到了字符串末尾的空格,也可能是夹在字符间的空格,需要额外处理。break;} else {// 其他非法字符return false;}index++;}// 处理末尾空格while (index < len && s.charAt(index) == ' ') {index++;}if (index == len && hasNum) {return true;}return false;}public boolean isNum(char c) {if (c >= '0' && c <= '9') return true;return false;}
}

24. LCR 157. 套餐内商品的排列顺序

这道题可以用深搜来做,还是用那一套模板,定义 flg 数组表示对应的 str[j] 是否被遍历过,注意去重可以用 是否是从左往右第一个未被填入的字符来判断( j > 0 && flg[j - 1] = false && flg[j - 1] == flg[j]),所以需要先对数组 str 进行排序,再从 0 下标开始遍历,如果该字符已经遍历过,或者不是从左往右第一个未被填入的字符,那就 continue,否则就将该字符 append 进 tmp 中,然后继续生成下一个位置的字符,然后就是回溯,将 flg[j] = false,并且将 str[j] 从 tmp 中删除。递归的出口就是当要生成的字符位置为 str.length 时,则说明字符生成完毕,将 tmp 添加进结果集合中,然后返回。

代码实现:

class Solution {List<String> arr;boolean[] flg;public String[] goodsOrder(String goods) {arr = new ArrayList<>();int len = goods.length();flg = new boolean[len];// 用深搜 + 回溯char[] str = goods.toCharArray();Arrays.sort(str);StringBuilder tmp = new StringBuilder();dfs(str, 0, len, tmp);String[] ret = new String[arr.size()];for (int i = 0; i < ret.length; i++) {ret[i] = arr.get(i);}return ret;}public void dfs(char[] str, int i, int len, StringBuilder tmp) {if (i == len) {// 说明已经生成完 len 个字符了arr.add(tmp.toString());return;}// 从 0 开始生成,第 i 位置的字符一共有 len 中可能性for (int j = 0; j < len; j++) {// 判断是否已经生成过该字符, 是否是从左往右第一个未被填入的字符if (flg[j] || (j > 0 && !flg[j - 1] && str[j - 1] == str[j])) {continue;}tmp.append(str[j]);flg[j] = true;// 生成下一个字符dfs(str, i + 1, len, tmp);// 回溯tmp.deleteCharAt(tmp.length() - 1);flg[j] = false;}}
}

25. LCR 167. 招式拆解 I

可以用滑动窗口和哈希表来做,定义 count 来记录最长连续不重复字符,定义 left 和 right 两个指针指向 0,用 set 来记录连续不重复字符,如果 arr[right] 是不重复字符,则添加到 set 里,然后 right++,直到遇到重复字符,那就先判断 set 的大小与 count 谁大,如果 set 大,则更新 count,然后再让 left 跳过重复字符,right++ 跳过重复字符,往后开始找新的连续不重复字符,最后返回 count 即可。

代码实现:

class Solution {public int dismantlingAction(String arr) {if (arr == null || arr.length() == 0) return 0;// 感觉可以用滑动窗口来做int count = 1;int left = 0;int right = 0;int len = arr.length();// set 用来记录连续不重复的字符Set<Character> set = new HashSet<>();while (right < len) {// 如果 arr[right] 不在 set 里,说明它不是重复字符// 则将 arr[right] 添加进 set 中,并让 right 往后走while (right < len && !set.contains(arr.charAt(right))) {set.add(arr.charAt(right++));}if (right >= len) {break;}// 如果 arr[right] 是重复字符 x ,则让 left 一直往后走// 直到跳过这个重复字符,然后最后再将重复字符 x 添加进 set 中// right 继续往后找连续不重复字符if (set.contains(arr.charAt(right))) {// 判断更新if (set.size() > count) {count = set.size();}// 出窗口char ch = arr.charAt(right);while (left < right && arr.charAt(left) != ch) {set.remove(arr.charAt(left++));}// set.remove(arr.charAt(left++));// set.add(ch);// left++ 跳过该重复字符left++;// 从重复字符往后开始找新的连续不重复字符right++;}}// 还需判断一次,防止漏掉最后的连续不重复字符if (set.size() > count) count = set.size();return count;}
}

26. LCR 169. 招式拆解 II

这个简单,用哈希表来做就行,记录每个字符出现的次数,然后再次遍历字符串,第一个出现次数为 1 的字母就是结果,如果到最后都没出现,则返回空格。

代码实现:

class Solution {public char dismantlingAction(String arr) {int[] hash = new int[26];for (int i = 0; i < arr.length(); i++) {char ch = arr.charAt(i);hash[ch - 'a']++;}for (int i = 0; i < arr.length(); i++) {char ch = arr.charAt(i);if (hash[ch - 'a'] == 1) {return ch;}}char c = ' ';return c;}
}

27. LCR 181. 字符串中的单词反转

这个也简单,整体思路就是先将整个字符串逆序,然后再分别逆序每个单词,可以用双指针来做,i 为 单词的开始下标,end 为单词的结束下标的下一个,先让 i 一直跳过空格找到字母或数字,然后 end 从 i 开始,只要不是空格,end 就往后走,当 end 停下来时,end - 1 就是单词结尾,逆序 i 到 end - 1 范围的字符,然后 i 再从 end 开始走。最后 i 重新遍历字符串数组,不是空格就一直添加进 ret 中,是空格就跳过,然后判断 i 是否越界,越界就跳出循环,然后如果 ret 不为空就添加一个空格到 ret 中,最后返回 ret.toString() 即可。

代码实现:

class Solution {public String reverseMessage(String message) {char[] arr = message.toCharArray();// 逆序整个字符串reverse(arr, 0, arr.length - 1);// 每个单词逆序int i = 0;while (i < arr.length) {// 跳过空格while (i < arr.length && arr[i] == ' ') {i++;}// 到这里 i 一定是数字或者字母int end = i;while (end < arr.length && arr[end] != ' ') {end++;}// 到这里 end 一定是空格,i 到 end - 1 则是单词reverse(arr, i, end - 1);i = end;}StringBuilder str = new StringBuilder();for (i = 0; i < arr.length; ) {while (i < arr.length && arr[i] != ' ') {str.append(arr[i++]);}while (i < arr.length && arr[i] == ' ') {i++;}// 防止句尾添加多余空格if (i >= arr.length) {break;}// 防止开头添加空格if (str.length() != 0) {str.append(' ');}}return str.toString();}public void reverse(char[] arr, int left, int right) {while (left < right) {char tmp = arr[left];arr[left++] = arr[right];arr[right--] = tmp;}}
}

28. LCR 182. 动态口令

这个也很简单,直接使用 substring 方法,截取字符串,最后拼接返回即可。

要是不让使用 substring 方法,那就自己遍历字符串即可。这个还可以简化一下,通过求余运算来简化。还有另一种方法,那就是先逆序整个字符串,然后再分别逆序 (0,len - t)  和 (len - t ,len)。

代码实现:

class Solution {public String dynamicPassword(String password, int target) {String str2 = password.substring(0, target);String str1 = password.substring(target);String ret = str1 + str2;return ret;}
}class Solution {public String dynamicPassword(String password, int target) {StringBuilder ret = new StringBuilder();for(int i = target; i < password.length(); i++){ret.append(password.charAt(i));}for(int i = 0; i < target; i++){ret.append(password.charAt(i));}return ret.toString();}
}
// 简化后
class Solution {public String dynamicPassword(String password, int target) {StringBuilder ret = new StringBuilder();for(int i = target; i < password.length() + target; i++){ret.append(password.charAt(i % password.length()));}return ret.toString();}
}// 逆序
class Solution {public String dynamicPassword(String password, int t) {// a b c d e  t = 2,len = 5// c d e a b  (2)// e d c b a  (3)// 要从 3 变到 2,需要逆序   (0,len - t)  和 (len - t, len)char[] arr = password.toCharArray();int len = arr.length;reverse(arr, 0, len - 1);reverse(arr, 0, len - 1 - t);reverse(arr, len - t, len - 1);return new String(arr);}public void reverse(char[] arr, int left, int right) {while (left < right) {char tmp = arr[left];arr[left++] = arr[right];arr[right--] = tmp;}}
}

29. LCR 192. 把字符串转换成整数 (atoi)

直接严格按照题目要求来写,

1. 首先跳过字符串的前导空格

2. 然后看下一个字符,是不是正号,负号

3. 然后再从下一个字符开始,一直读数字字符,如果该字符不是数字字符,就直接返回

4. 将上面读到的数字串转化为 int,且跳过前导 0。

5. 如果最后数字大于 int 最大值,返回 int 最大值,如果数字小于 int 最小值,返回 int 最小值,如果没有读到数字,返回 0。

代码实现:

class Solution {public int myAtoi(String str) {int i = 0;int len = str.length();// 是否是负数boolean flg = false;// 记录正负号数量int flgOp = 0;// 记录数字串StringBuilder num = new StringBuilder();// 跳过前导空格while (i < len && str.charAt(i) == ' ') {i++;}// 下一个字符是否是正负号,如果正负号或点号大于等于 2,则返回 0if (i < len && str.charAt(i) == '-') {flgOp++;flg = true;i++;}if (i < len && str.charAt(i) == '+') {flgOp++;i++;}// 如果该字符不是数字,则返回 0if (i < len && !isNum(str.charAt(i))) {return 0;}// 记录 从 i 开始一直到非数字的整个数字范围int end = i;while (end < len && isNum(str.charAt(end))) {end++;}String tmp = str.substring(i, end);// 添加进数字字符串中num.append(tmp);// 到这里就是非数字部分,直接退出// 正负号数量大于 1,则说明字符串不合法if (flgOp >= 2) {return 0;}double sum = 0;// 用 i 遍历 num 数字串i = 0;// 根据 num 字符串,计算结果// 跳过前导 0while (i < num.length() && num.charAt(i) == '0') {i++;}while (i < num.length()) {int t = num.charAt(i) - '0';sum = (sum * 10 + t);i++;}// 如果是负数if (flg) {sum *= -1;}if (sum > Integer.MAX_VALUE - 1) {return Integer.MAX_VALUE;} else if (sum < Integer.MIN_VALUE) {return Integer.MIN_VALUE;} else {return (int) sum;}}public boolean isNum(char c) {return c >= '0' && c <= '9';}
}

链表

30. LCR 123. 图书整理 I

这个简单,直接翻转链表,然后添加到数组中即可。

还可以用递归实现。

代码实现:

class Solution {public int[] reverseBookList(ListNode head) {if (head == null) return new int[0];// 头插法ListNode prev = head;ListNode cur = head.next;prev.next = null;int len = 1;while (cur != null) {ListNode curNext = cur.next;cur.next = prev;prev = cur;cur = curNext;len++;}int[] ret = new int[len];int i = 0;cur = prev;while (cur != null) {ret[i++] = cur.val;cur = cur.next;}return ret;}
}// 递归
class Solution {public int[] reverseBookList(ListNode head) {getList(head);int[] ret = new int[arr.size()];for (int i = 0; i < ret.length; i++) {ret[i] = arr.get(i);}return ret;}public List<Integer> arr = new ArrayList<>();public void getList(ListNode cur) {if (cur == null) return;getList(cur.next);arr.add(cur.val);}
}

31. LCR 136. 删除链表的节点

这道题很简单,只要删除第一次出现的 val 元素即可,定义两个指针 prev 和 cur,prev 指向 cur 的前一个元素,cur 遍历链表,如果此时 cur.val == val,那就删除 cur,然后直接返回头节点,否则就让 prev 和 head 一直往后走,到最后,如果 head.val == val,那就返回 head.next 即可。

代码实现: 

class Solution {public ListNode deleteNode(ListNode head, int val) {if (head == null) return null;ListNode prev = head;ListNode cur = head.next;while (cur != null) {if (cur.val == val) {prev.next = cur.next;cur = cur.next;return head;} else {prev = cur;cur = cur.next;}}if (head.val == val) head = head.next;return head;}
}

32. LCR 140. 训练计划 II

这个可以用快慢指针来做,定义 slow 和 fast 指向 head,先让 fast 走 cnt - 1 步,然后再让 fast 和 slow 一起走,当 fast 走到链表最后一个节点的位置时,slow 就是倒数第 cnt 个节点的位置。

代码实现:

class Solution {public ListNode trainingPlan(ListNode head, int cnt) {ListNode fast = head;ListNode slow = head;while (cnt - 1 != 0) {fast = fast.next;if (fast == null) {return null;}cnt--;}while (fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}
}

33. LCR 141. 训练计划 III

这个简单,直接逆序链表,采用头插法即可。

代码实现:

class Solution {public ListNode trainningPlan(ListNode head) {// 采用头插法即可if (head == null || head.next == null) return head;ListNode prev = head;ListNode cur = head.next;// 防止代码成环prev.next = null;while (cur != null) {ListNode curNext = cur.next;cur.next = prev;prev = cur;cur = curNext;}return prev;}
}

34. LCR 142. 训练计划 IV

思路跟合并有序链表大差不差。

代码实现:

class Solution {public ListNode trainningPlan(ListNode l1, ListNode l2) {if (l1 == null) return l2;if (l2 == null) return l1;// 虚拟头节点,返回时返回 dummy.nextListNode dummy = new ListNode(-1);ListNode cur = dummy;// 其实跟合并有序数组差不多while (l1 != null && l2 != null) {if (l1.val < l2.val) {cur.next = l1;l1 = l1.next;cur = cur.next;} else {cur.next = l2;l2 = l2.next;cur = cur.next;}}if (l1 != null) {cur.next = l1;}if (l2 != null) {cur.next = l2;}return dummy.next;}
}

35. LCR 171. 训练计划 V

找链表相交节点,这个可以用快慢指针来做,先让 fast 走差值步,然后 fast 和 slow 一起走,当 fast 和 slow 相遇时,就是链表相交节点。

代码实现:

class Solution {ListNode getIntersectionNode(ListNode headA, ListNode headB) {if (headA == null || headB == null) return null;int countA = 0;int countB = 0;ListNode fast = headA;ListNode slow = headB;while (fast != null) {fast = fast.next;countA++;}while (slow != null) {slow = slow.next;countB++;}fast = headA;slow = headB;int len = countA - countB;if (len < 0) {len = countB - countA;fast = headB;slow = headA;}while (len != 0) {fast = fast.next;len--;}while (fast != slow) {fast = fast.next;slow = slow.next;}return fast;}
}

36. LCR 154. 复杂链表的复制

让你复制一份链表,可以用哈希表来做,将老节点与新节点的对应关系存入哈希表中,最后重新遍历链表,根据哈希表来获取新节点,然后建立联系即可。

代码实现:

class Solution {public Node copyRandomList(Node head) {if (head == null) return null;Node dummy = new Node(-1);Node cur = head;Map<Node, Node> hash = new HashMap<>();// 将老节点与新节点的关系存起来while (cur != null) {Node node = new Node(cur.val);hash.put(cur, node);cur = cur.next;}cur = head;while (cur != null) {hash.get(cur).next = hash.get(cur.next);hash.get(cur).random = hash.get(cur.random);cur = cur.next;}return hash.get(head);}
}

栈和队列

37. LCR 147. 最小栈

可以用两个栈来实现,一个栈当做正常的栈,另一个栈来存储最小值的栈。

入栈时,正常栈正常入栈,如果最小栈为空,那么也入栈,如果不为空,那么入栈的值 val 就需要与最小栈的栈顶元素比较,如果小于等于栈顶元素,那么 val 就入最小栈。

出栈时,首先需要判断两个栈是否为空,如果两个栈都为空,则不能出栈,否则正常栈正常出栈即可。获取栈顶元素也同理。

如果是获取最小栈栈顶元素,那还是得先判断最小栈是否为空,为空的话返回 -1,如果不为空,直接返回最小栈.peek() 即可。

代码实现:

class MinStack {// 可以用一个栈当正常栈// 一个栈当最小栈Stack<Integer> s1 = new Stack<>();Stack<Integer> s2 = new Stack<>();/*** initialize your data structure here.*/public MinStack() {s1 = new Stack<>();s2 = new Stack<>();}public void push(int x) {s1.push(x);if (s2.empty()) {s2.push(x);} else {int top = s2.peek();if (x <= top) {s2.push(x);}}}public void pop() {if (s1.empty()) {return;}int top = s1.pop();if (!s2.empty() && s2.peek() == top) {s2.pop();}}public int top() {if (s1.empty()) {return -1;}return s1.peek();}public int getMin() {if (s2.empty()) {return -1;}return s2.peek();}
}

38. LCR 125. 图书整理 II

简单来说,就是让你用栈实现队列,那这个也简单,大体思路就是:直接定义两个栈,固定一个栈 1 入元素,另一个栈 2 出元素,如果栈 2 为空,那么就把栈 1 的所有元素出栈,并入到栈 2 2中,此时 栈 2 再出栈。

代码实现:

class CQueue {// 用栈来实现队列Stack<Integer> s1 = new Stack<>();Stack<Integer> s2 = new Stack<>();public CQueue() {s1 = new Stack<>();s2 = new Stack<>();}public void appendTail(int value) {s1.push(value);}public int deleteHead() {if (s1.empty() && s2.empty()) {return -1;}if (s2.empty()) {while (!s1.empty()) {s2.push(s1.pop());}}return s2.pop();}
}

39. LCR 184. 设计自助结算系统

这道题的难点是如何用 O(1) 的时间获取的最大值,因为最大值的候补者有许多个,如何在删除最大值的时候,快速找到下一个最大值。我们可以用普通队列和双端队列实现,双端队列用来存储最大值的候补者,并将这些最大值的候补者按照降序来排序,那么双端队列的第一个元素就一定是最大值。而普通队列就正常进行操作就行,但是双端队列进行操作时就需要进行判断。

在新增元素时,双端队列如果为空,那么该元素可能是最大值,则从尾巴入队。如果双端队列不为空,就需要判断队列的尾巴元素与当前元素 val 比较,如果 val 比尾巴元素要大,则说明尾巴元素就一定不可能是最大值了,所以一直出队,直到遇到尾巴元素比当前元素 val 大,或者等于当前元素。那么此时当前元素就可以从尾巴入队了。

删除元素时,首先判断正常队列是否为空,如果为空,则直接返回,如果不为空,则正常队列出队得到了 top 元素,还需要去看看双端队列的头元素是否与 top 相同,如果相同,则双端队列把头元素出队。

代码实现:

class Checkout {// 可以用队列和双端队列实现Queue<Integer> queue;// 双端队列存储可能是最大值的元素,并且按照降序存储Deque<Integer> maxQueue;public Checkout() {queue = new LinkedList<>();maxQueue = new LinkedList<>();}public int get_max() {if (maxQueue.isEmpty()) {return -1;}// 取出双端队列的头元素就是最大值return maxQueue.peekFirst();}public void add(int value) {queue.offer(value);// 如果双端队列为空,则当前元素可能是最大值,入队if (maxQueue.isEmpty()) {maxQueue.offerLast(value);return;}// 如果不为空,则需要判断,如果当前 val 大于双端队列的尾巴元素,// 说明此时双端队列的尾巴元素一定不可能是最大值,要保持最大值降序排序// 那就把双端队列的尾巴元素删掉,然后把 val 添加进来while (!maxQueue.isEmpty() && value > maxQueue.peekLast()) {maxQueue.pollLast();}maxQueue.offerLast(value);}public int remove() {if (queue.isEmpty()) {return -1;}// 删除时也同理,需要判断删除的元素是否与 max 的头元素相同,// 如果相同,则 max 也需要出队int top = queue.poll();if (top == maxQueue.peekFirst()) {maxQueue.pollFirst();}return top;}
}

40. LCR 148. 验证图书取出顺序

这道题不难,就是遍历入栈数组,先将里面的元素入栈,然后判断栈顶元素与出栈元素是否相同,如果是,那就出栈,并且用 j 来遍历出栈数组,j++。

如果最后栈里为空,则返回 true,否则返回 false。

代码实现:

class Solution {public boolean validateBookSequences(int[] putIn, int[] takeOut) {Stack<Integer> stack = new Stack<>();int j = 0;for (int i = 0; i < putIn.length; i++) {stack.push(putIn[i]);while (!stack.empty() && stack.peek() == takeOut[j]) {stack.pop();j++;}}if (stack.empty()) {return true;}return false;}
}

41. LCR 124. 推理二叉树

代码实现:

class Solution {public int preIndex;public TreeNode deduceTree(int[] preorder, int[] inorder) {TreeNode root = createTree(inorder, preorder, 0, preorder.length - 1);return root;}public TreeNode createTree(int[] inorder, int[] preorder, int start, int end) {if (start > end) return null;TreeNode root = new TreeNode(preorder[preIndex]);// 找下标int rootIndex = getRootIndex(inorder, start, end, preorder[preIndex]);preIndex++;if (rootIndex == -1) return root;// 按照前序遍历来创建二叉树root.left = createTree(inorder, preorder, start, rootIndex - 1);root.right = createTree(inorder, preorder, rootIndex + 1, end);return root;}// 在中序遍历中找到根节点public int getRootIndex(int[] inorder, int start, int end, int key) {for (int i = start; i <= end; i++) {if (inorder[i] == key) {return i;}}return -1;}
}

42. LCR 143. 子结构判断

这道题思路跟找子树差不多,区别就是找子树时,树 1 和树 2 的结构必须完全相同,并且对应的值也必须相同,但是这里如图例 2 ,这里当树 2 为空时,树 1 可以不为空。所以在写找子树代码时还可以分以下情况,修改修改。

总体思路就是,找子树,子树要结构相同,并且值相同,左子树相同并且右子树相同才是子树,可以用前序遍历来做,每遍历到一个节点,都去看看当前节点是否就是子树。但是得注意,当两棵树都为空时,要返回 false。

代码实现: 

class Solution {public boolean isSubStructure(TreeNode A, TreeNode B) {// 题目要求,如果两棵树都为空,则返回 falseif (A == null && B == null) {return false;}if (A == null && B != null || A != null && B == null) return false;return isSubTree(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);}public boolean isSubTree(TreeNode p, TreeNode q) {// 1. 值相同  2. 结构相同if (p == null && q == null) return true;if (p == null && q != null) return false;// 当 q 为空时,p 可以不为空if (p != null && q == null) return true;// 值不相同if (p.val != q.val) return false;return isSubTree(p.left, q.left) && isSubTree(p.right, q.right);}
}

43. LCR 144. 翻转二叉树

这个很简单,就是左子树跟右子树交换即可。用前序遍历,每一个节点的左孩子和右孩子交换即可。

代码实现:

class Solution {public TreeNode mirrorTree(TreeNode root) {if (root == null) return null;TreeNode tmp = root.left;root.left = root.right;root.right = tmp;mirrorTree(root.left);mirrorTree(root.right);return root;}
}

44. LCR 145. 判断对称二叉树

这道题就是判断二叉树是否对称,前提条件就是得判断结构对称,并且值也得对称,并且左孩子 1的左孩子 2 和右孩子 1 的右孩子 2 对称,并且左孩子 1 的右孩子 2 与右孩子 1 的左孩子 2 对称。

代码实现:

class Solution {public boolean checkSymmetricTree(TreeNode root) {if (root == null) return true;return isSymmetricTree(root.left, root.right);}public boolean isSymmetricTree(TreeNode p, TreeNode q) {// 1. 结构相同 2. 值相同if (p == null && q == null) return true;if (p == null && q != null || p != null && q == null) return false;if (p.val != q.val) return false;// 对称,如图示例一return isSymmetricTree(p.left, q.right) && isSymmetricTree(p.right, q.left);}
}

45. LCR 149. 彩灯装饰记录 I

就是二叉树层序遍历,利用队列实现即可,如果队列不为空,那就先出队 top,如果左子树不为空,那就将左子树入队,如果右子树不为空,那就将右子树入队,然后再将 top 添加到数组中,最后返回数组即可。

代码实现:

class Solution {public int[] decorateRecord(TreeNode root) {if (root == null) return new int[0];Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);List<Integer> arr = new ArrayList<>();while (!queue.isEmpty()) {TreeNode top = queue.poll();arr.add(top.val);if (top.left != null) {queue.offer(top.left);}if (top.right != null) {queue.offer(top.right);}}int[] ret = new int[arr.size()];for (int i = 0; i < ret.length; i++) {ret[i] = arr.get(i);}return ret;}
}

46. LCR 150. 彩灯装饰记录 II

与上一题代码基本一致,就是在进入循环时,判断队列中有多少元素 size,队列中 size 的个数就是这一层节点的个数,然后循环出队 size 次,就把这层节点元素全部拿到了,最后添加进数组中,然后返回数组即可。

代码实现:

class Solution {public List<List<Integer>> decorateRecord(TreeNode root) {List<List<Integer>> ret = new ArrayList<>();if (root == null) return ret;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {List<Integer> arr = new ArrayList<>();int size = queue.size();while (size != 0) {TreeNode top = queue.poll();arr.add(top.val);if (top.left != null) {queue.offer(top.left);}if (top.right != null) {queue.offer(top.right);}size--;}ret.add(arr);}return ret;}
}

47. LCR 151. 彩灯装饰记录 III

跟层序遍历差不多,就是逆转了下双数层的值的顺序,可以利用 Collections.reverse 方法来完成。

代码实现:

class Solution {public List<List<Integer>> decorateRecord(TreeNode root) {List<List<Integer>> ret = new ArrayList<>();if (root == null) return ret;Queue<TreeNode> queue = new LinkedList<>();queue.add(root);boolean flg = true;while (!queue.isEmpty()) {int size = queue.size();List<Integer> arr = new ArrayList<>();while (size != 0) {TreeNode top = queue.poll();arr.add(top.val);if (top.left != null) {queue.add(top.left);}if (top.right != null) {queue.add(top.right);}size--;}if (!flg) {Collections.reverse(arr);}flg = !flg;ret.add(arr);}return ret;}
}

48. LCR 152. 验证二叉搜索树的后序遍历序列

二叉搜索树就是左子树小于根节点,右子树大于根节点,所以只需要判断通过递归来判定所有节点都符合上面的要求,那么这棵树就是二叉搜索树。先划分左右子树的区间,找到第一个右子树的节点(节点值大于根节点),然后再判断右子树区间的值是否全都比根节点大,如果不是,返回 false,如果是,则递归去判断左子树和右子树。

代码实现:

class Solution {public boolean verifyTreeOrder(int[] postorder) {return verifyTreeOrder(postorder, 0, postorder.length - 1);}public boolean verifyTreeOrder(int[] postorder, int start, int end) {if (start >= end) return true;// 以 end 为根节点,划分左子树和右子树int root = postorder[end];// 往后找大于 root 的值, 找到第一个右子树节点int cur = start;while (postorder[cur] < postorder[end]) cur++;// 此时 postorder[cur] 一定大于 rootint mid = cur;// mid, end 就是右子树范围while (postorder[cur] > postorder[end]) cur++;// 到这里,start, mid - 1 是左子树,  m,end - 1 是右子树return cur == end && verifyTreeOrder(postorder, start, mid - 1) && verifyTreeOrder(postorder, mid, end - 1);}
}

49. LCR 153. 二叉树中和为目标值的路径

可以用深搜来做,定义一个数组 arr 来存放遍历的节点,定义一个 sum 用来记录当前遍历过所有节点的和,用前序遍历去遍历每一个节点,先将 root 的值添加进 arr 和 sum 中,如果 sum 等于 target 并且此时是叶子节点,就添加进返回结果中,然后再删除数组 arr 当前节点,sum 减等当前节点值,最后返回结果,其他情况就继续遍历左子树,并将遍历的结果添加进返回结果中,右子树同理,最后再删除 arr 里当前节点值,sum 减去当前节点值,最后再返回结果即可。

代码实现:

class Solution {public List<List<Integer>> pathTarget(TreeNode root, int target) {dfs(root, target);return ret;}public int sum = 0;public List<Integer> arr = new ArrayList<>();public List<List<Integer>> ret = new ArrayList<>();public void dfs(TreeNode root, int target) {if (root == null) return;arr.add(root.val);sum += root.val;if (sum == target && root.left == null && root.right == null) {ret.add(new ArrayList<>(arr));arr.remove(arr.size() - 1);sum -= root.val;return;}dfs(root.left, target);dfs(root.right, target);arr.remove(arr.size() - 1);sum -= root.val;}
}

50. LCR 155. 将二叉搜索树转化为排序的双向链表

将二叉搜索树转化为排序的双向链表,可以利用二叉搜索树的中序遍历是有序的特点,可以定义 cur 和 prev 两个指针,prev 是 cur 的中序遍历的前一个节点,先递归往 cur 的右边走,然后判断 prev 是否为空,如果为空,说明此时 cur 就是链表头节点,记录一下。如果不为空,就可以进行修改指向了,prev.right = cur。 cur.left = prev,然后再让 prev 往后走,继续递归 cur 的右边。递归结束后,prev 就是链表的尾巴节点,只需要修改一下链表头节点和尾巴节点的指向,最后再返回即可。

代码实现:  

class Solution {public Node treeToDoublyList(Node root) {if (root == null) return null;dfs(root);// 最后 prev 一定就是尾巴节点head.left = prev;prev.right = head;return head;}public Node prev = null;public Node head = null;// 中序遍历public void dfs(Node cur) {if (cur == null) return;dfs(cur.left);if (prev == null) {head = cur;} else {prev.right = cur;}cur.left = prev;// prev 往后走prev = cur;dfs(cur.right);}
}

51. LCR 156. 序列化与反序列化二叉树

序列化就是将二叉树转化成字符串,反序列化就是将字符串转化成二叉树,这道题可以用层序遍历来做,在序列化时,可以将节点为空的情况也添加到字符串中,每个节点以逗号分隔。

可以从第一层节点开始,从左到右从上到下都编一个号,从 0 开始编号,那么当前节点 cur 编号为 i,则 2*i + 1 是 cur 的左孩子,2*i + 2 是 cur 右孩子,根据这个来进行反序列化,因为是按照层序遍历的方式序列化的,所以也是按照层序遍历的方式来反序列化,将创建的节点都添加到队列中,先按照 "," 来分隔字符串,这样每个字符串 str[i] 就都是一个节点,i 从 0 开始,如果队列不为空,就出队一个元素 top,如果 top 不为空,说明 top 是一个节点,就说明 top 可能会有左右孩子,就分别判断 2*i + 1 和 2*i + 2 是否越界,如果没有越界,并且对应的 str[2*i + 1] 不为空和 str[2*i + 2] 不为空,则说明存在左孩子或者右孩子,则将左孩子和右孩子添加进队列中,并让 top 的 left 和 right 分别指向左右孩子。然后 i++ 往后走,最后返回 root 即可。

代码实现:

public class Codec {// Encodes a tree to a single string.public String serialize(TreeNode root) {if (root == null) return "[]";// 可以利用层序遍历实现Queue<TreeNode> queue = new LinkedList<>();StringBuilder str = new StringBuilder("[");queue.offer(root);while (!queue.isEmpty()) {TreeNode top = queue.poll();if (top != null) {str.append(top.val + ",");queue.offer(top.left);queue.offer(top.right);} elsestr.append("null,");}str.deleteCharAt(str.length() - 1);str.append("]");return str.toString();}// Decodes your encoded data to tree.public TreeNode deserialize(String data) {if (data.equals("[]")) {return null;}// 点号分隔,那就是每个节点 [1,2,3,null,null,4,5,null,null]String[] arr = data.substring(1, data.length() - 1).split(",");TreeNode root = new TreeNode(Integer.valueOf(arr[0]));// 用层序遍历的方式解析// 从 0 下标开始编号,如果该节点不为空,则:// 左子树 2*i + 1// 右子树 2*i + 2Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);int i = 0;while (!queue.isEmpty()) {TreeNode top = queue.poll();if (2 * i + 1 < arr.length && !arr[2 * i + 1].equals("null")) {TreeNode left = new TreeNode(Integer.valueOf(arr[2 * i + 1]));queue.offer(left);top.left = left;}if (2 * i + 2 < arr.length && !arr[2 * i + 2].equals("null")) {TreeNode right = new TreeNode(Integer.valueOf(arr[2 * i + 2]));queue.offer(right);top.right = right;}// i++ 去遍历后一个节点i++;}return root;}
}

52. LCR 174. 寻找二叉搜索树中的目标节点

一眼看到求第 k 大元素,那就可以用优先级队列来解决,创建小根堆,用前序遍历,当小堆元素个数小于 cnt 时,那就入堆,如果元素个数大于等于 cnt,那就判断一下 root.val 与堆顶元素谁大,如果 root.val 大,那么小堆出队,然后将 root.val 添加进小堆中,然后继续遍历左子树和右子树。

遍历完成后,小堆的堆顶元素就是第 cnt 大元素。

代码实现:

class Solution {public int findTargetNode(TreeNode root, int cnt) {PriorityQueue<Integer> queue = new PriorityQueue<>();getKMax(root, cnt, queue);return queue.peek();}public int i;public void getKMax(TreeNode root, int cnt, PriorityQueue<Integer> queue) {if (root == null) return;if (i < cnt) {queue.offer(root.val);} else {int top = queue.peek();int val = root.val;if (val > top) {queue.poll();queue.offer(val);}}i++;getKMax(root.left, cnt, queue);getKMax(root.right, cnt, queue);}
}

看了大佬的题解后,发现可以利用二叉搜索树的中序遍历是有序的来做,求第 K 大元素,那我们就可以中序遍历反着遍历,此时遇到的第 K 个元素就是第 K 大元素。

代码实现:

class Solution {public int findTargetNode(TreeNode root, int cnt) {getMax(root, cnt);return kMax;}public int i = 1;public int kMax = 0;public void getMax(TreeNode root, int cnt) {if (root == null) return;// 中序:  左根右// 反着来:右根左getMax(root.right, cnt);if (i == cnt) {kMax = root.val;}i++;if (i > cnt) return;getMax(root.left, cnt);}
}

53. LCR 175. 计算二叉树的深度

这个很简单,让你计算二叉搜索树的高度,可以用递归来做,整棵树的高度就等于左子树高度和右子树的高度的最大值,再加上自己这个节点本身,也就是 +1 。

代码实现:

class Solution {public int calculateDepth(TreeNode root) {if (root == null) return 0;int leftHeight = calculateDepth(root.left);int rightHeight = calculateDepth(root.right);return Math.max(leftHeight, rightHeight) + 1;}
}

54. LCR 176. 判断是否为平衡二叉树

这个也很简单,可以在计算树的高度的时候,去判断是否是平衡二叉树。如果是,则正常返回高度,如果不是,则返回 -1 即可,最后只需要判断得到的高度是否大于等于 0。 

代码实现:

class Solution {public boolean isBalanced(TreeNode root) {// 可以在计算树的高度时,也判断是否是平衡二叉树return getHeight(root) >= 0;}public int getHeight(TreeNode root) {if (root == null) return 0;int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);if (leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight - rightHeight) <= 1) {return Math.max(leftHeight, rightHeight) + 1;} else {// 说明不是平衡二叉树,那高度返回负数即可return -1;}}
}

55. LCR 193. 二叉搜索树的最近公共祖先

这道题得分情况讨论,第一种情况是 p == root 或者 q == root,则此时最近公共祖先就是 root

第二种情况是如果 p 和 q 都在 root 的左边,或者 p 和 q 都在 root 的右边,如例子2,就看谁在前头就是谁。

第三种情况就是 p 和 q 分别在 root 的两边,那此时这种情况最近公共祖先就是 root,如例子1。

代码实现:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {// 分三种情况,第一种是 p 或者 q 中有一个是 root// 一种是 p 和 q 都在 root 的左边或者右边// 另一种是 p 和 q 分别在 root 的两边if (root == p || root == q) return root;if (root == null || p == null || q == null) return null;TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);if (left != null && right != null) {return root;} else if (left == null) {return right;} else {return left;}}
}

56. LCR 194. 二叉树的最近公共祖先

这道题和上面那道题是解法一模一样,还有另一种做法。

如图:

代码实现:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null) return null;Stack<TreeNode> s1 = new Stack<>();Stack<TreeNode> s2 = new Stack<>();getPath(root, p, s1);getPath(root, q, s2);int len = s1.size() - s2.size();if (len < 0) {len = s2.size() - s1.size();while (len != 0) {s2.pop();len--;}} else {while (len != 0) {s1.pop();len--;}}while (!s1.empty() && !s2.empty()) {TreeNode top1 = s1.pop();TreeNode top2 = s2.pop();if (top1 == top2) return top1;}return null;}public boolean getPath(TreeNode root, TreeNode target, Stack<TreeNode> stack) {if (root == null) return false;stack.push(root);if (root == target) return true;boolean left = getPath(root.left, target, stack);if (left) return true;boolean right = getPath(root.right, target, stack);if (right) return true;// 到这里说明左子树和右子树都没找到 target// 说明不是路径上的节点, 删除节点返回 falsestack.pop();return false;}
}

位运算

57. LCR 133. 位 1 的个数

这个简单,直接利用 n &= (n - 1) 消除 n 中二进制 1 的个数,并且用计数器记录下来即可。

代码实现:

public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int count = 0;while (n != 0) {n &= (n - 1);count++;}return count;}
}

58. LCR 134. Pow(x, n)

可以用快速幂来做,就是 x^n = (x*x)^(n/2)(n 为偶数)或者 x*(x*x)^(n/2)

那就可以利用这个来做题。

代码实现:

class Solution {public double myPow(double x, int n) {if (x == 0.0) return 0.0;// 用快速幂// 2^9 = (2)* 4^4 = (2)* 16^2 = (2)* 256^1 = (2*256)* (256*256)^0 = 512// 用来记录多出来的 x,也就是当 n 为奇数时,res *= xdouble res = 1.0;boolean flg = false;// n 可能会很大,将 n 赋给 tmp 防止越界(-2147483648)long tmp = n;if (tmp < 0) {tmp = -tmp;flg = true;}while (tmp != 0) {if (tmp % 2 == 1) {res *= x;}x = x * x;tmp /= 2;}if (flg) {return 1.0 / res;}return res;}
}

59. LCR 177. 撞色搭配

这个可以用分组异或的方式来做,先将数组所有元素异或一遍 得到 ret,ret 中的二进制为 1 的那一位说明就是两个只出现一次的数字的区分点,然后根据这个区分点,来分组异或,最后返回异或得到的结果即可。

代码实现:

class Solution {public int[] sockCollocation(int[] sockets) {int tmp = 0;for (int i = 0; i < sockets.length; i++) {tmp ^= sockets[i];}// 分组异或int index = 0;while (tmp != 0) {if (tmp % 2 == 1) {break;}tmp >>= 1;index++;}int num1 = 0;int num2 = 0;for (int i = 0; i < sockets.length; i++) {if (((sockets[i] >> index) & 1) == 1) {num1 ^= sockets[i];} else {num2 ^= sockets[i];}}return new int[]{num1, num2};}
}

60. LCR 178. 训练计划 VI

这道题可以用哈希表来做,不会超时,遍历数组记录每个数字出现的次数,然后再次遍历数组,如果当前数字出现了一次,就返回该数字。

代码实现:

class Solution {public int trainingPlan(int[] actions) {Map<Integer, Integer> hash = new HashMap<>();for (int i = 0; i < actions.length; i++) {int value = hash.getOrDefault(actions[i], 0);hash.put(actions[i], value + 1);}for (int i = 0; i < actions.length; i++) {int value = hash.getOrDefault(actions[i], 0);if (value == 1) {return actions[i];}}return -1;}
}

61. LCR 190. 加密运算

这个就是让你求两个数的和,但是不能使用加减乘除,那就可以使用位运算来做,a ^ b 就是 a 和 b 不进位相加的和,那我们可以定义一个变量来记录 a 和 b 的进位,然后就一直进行异或直到进位为 0.

3 和 5

  011       3

  101       5

  001   a & b 这就是进位,需要往前进位, 001 -->  010,所以两数之和 = 不进位和 + 进位和

           所以进位的计算公式为 (a & b) << 1 

  010   (a & b) << 1 

  110   a ^ b    

  100   上面两个异或之后得到不进位和,再求进位

  100   (a & b) << 1   进位

0000   上面两个异或之后得到不进位和,再求进位

1000   (a & b) << 1   进位

1000   异或和

0000   进位,当进位为 0,上面两数之和计算完毕

代码实现:

class Solution {public int encryptionCalculate(int dataA, int dataB) {if (dataA == 0) return dataB;if (dataB == 0) return dataA;// 两个数不进位相加的结果  a ^ bwhile (dataB != 0) {int carry = (dataA & dataB) << 1; // 计算进位dataA = dataA ^ dataB;// 计算两数不进位相加和dataB = carry;}return dataA;}
}

动态规划

62. LCR 126. 斐波那契数

这个很简单,公式给你了,按照公式求解就行。

代码实现:

class Solution {public int fib(int n) {if (n == 0 || n == 1) return n;int a = 0;int b = 1;int c = 0; while (n >= 2) {c = (a + b) % 1000000007;a = b;b = c;n--;}return c;}
}

63. LCR 127. 跳跃训练

这个很简单,就是青蛙跳台阶问题,跟斐波那契问题的解法一模一样。

代码实现:

class Solution {public int trainWays(int num) {if (num < 2) return 1;int[] dp = new int[num + 1];dp[0] = 1;dp[1] = 1;for (int i = 2; i <= num; i++) {dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;}return dp[num];}
}

64. LCR 137. 模糊搜索验证

这道题用动态规划来做,大体分两种情况,当 input 的第 j-1 个字符是 * 以及不是 * 的情况。

首先是明确 dp[i][j],根据题目可知表示以 article 的第 i 个字符结尾的串与以 input 的第 j 个字符结尾的串是否匹配。然后推导状态转移方程 dp[i][j] = ?

当 input[j - 1] != '*' 时,如果 article[i-1] == input[j-1] 或者有个字符是点号,则 dp[i][j] = dp[i - 1][j - 1] (看以 article 的第 i 个字符结尾的串与以 input 的第 j 个字符结尾的串的状态)

当 input[j - 1] 等于 '*' 时,dp[i][j] = dp[i][j-2] (因为 input[j-1] 是 '*', 所以关注 intput[j - 2] 结尾的串即可),如果 article[i-1] == input[j-2] 或者其中一个字符是'*' 或者点号,则 dp[i][j] = dp[i][j] || dp[i - 1][j]。初始化就是当两字符串都是空串时,dp[0][0] = true。

代码实现:

class Solution {public boolean articleMatch(String a, String b) {// 用动态规划来做,dp[i][j] 代表在 a 中以 i 个字符结尾的字符串与在 b 中第 j 个字符结尾的字符串是否匹配int len1 = a.length();int len2 = b.length();boolean[][] dp = new boolean[len1 + 1][len2 + 1];// 初始化dp[0][0] = true;char[] arr1 = a.toCharArray();char[] arr2 = b.toCharArray();for (int i = 0; i <= len1; i++) {for (int j = 1; j <= len2; j++) {if (arr2[j - 1] == '*') {dp[i][j] = dp[i][j - 2];if (i > 0) {if (charMatch(arr1[i - 1], arr2[j - 2])) {dp[i][j] = dp[i][j] || dp[i - 1][j];}}} else {if (i > 0 && charMatch(arr1[i - 1], arr2[j - 1])) {dp[i][j] = dp[i - 1][j - 1];}}}}return dp[len1][len2];}public boolean charMatch(char a, char b) {if (a == '*' || b == '*' || a == '.' || b == '.') return true;return a == b;}
}

65. LCR 161. 连续天数的最高销售额

这道题可以用动态规划来做,求连续数组最大和,dp[i] 就是以 i 下标结尾天数的最大和。

dp[i] = Math.max(sales[i], dp[i - 1] + sales[i]),因为 sales[i] 可能是负数。

初始化,dp[0] = sales[0],最后遍历 dp 找最大值并返回即可。

代码实现:

class Solution {public int maxSales(int[] sales) {// dp[i] 表示以 i 下标结尾的天数的最大和int[] dp = new int[sales.length];dp[0] = sales[0];for (int i = 1; i < dp.length; i++) {dp[i] = Math.max(dp[i - 1] + sales[i], sales[i]);}int max = Integer.MIN_VALUE;for (int i = 0; i < dp.length; i++) {if (dp[i] > max) {max = dp[i];}}return max;}
}

66. LCR 165. 解密数字

这道题也可以用动态规划来做,dp[i] 代表以第 i 个数字结尾的字符串有多少种解密方案。

 一个数字就代表一个字母,但是这个数字范围是 0-25。

所以根据数字,这个解密方式 dp[i] = dp[i - 1]。当 str[i - 1] 和 str[i] 能够组合数字时(num >= 10 && num <= 25),则 dp[i] = dp[i - 1] + dp[i - 2] 。

初始化,dp[0] = dp[1] = 1。那这里跟斐波那契问题有点像,就可以定义三个变量 a,b,c 来替代 dp 数组。

代码实现:

class Solution {public int crackNumber(int ciphertext) {String str = String.valueOf(ciphertext);// int[] dp = new int[str.length() + 1];// dp[i] 表示以第 i 个字符结尾的解密方案数量int a = 1, b = 1, c = 1;int len = str.length();int i = 2;while (i <= len) {c = b;// 如果 str[i - 2] 存在, 则可以组合 str[i - 2]str[i - 1]String tmp = str.substring(i - 2, i);if (tmp.compareTo("10") >= 0 && tmp.compareTo("25") <= 0) {c += a;}a = b;b = c;i++;}return c;}
}

67. LCR 166. 珠宝的最高价值

可以用动态规划来做,先定义 dp[i][j] 为从 frame[0][0] 到 frame[i][j] 的珠宝最大值,然后再来推断dp[i][j] = ?,到达 dp[i][j] 有两种可能,第一种是从上面来到,第二种是从左边来的。

所以 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + frame[i][j] 。但还要考虑边界情况比如在左上角和在右上角的情况,此时就只有一个方向。最后就是初始化 dp[0][0] = frame[0][0]

代码实现:

class Solution {public int jewelleryValue(int[][] frame) {int row = frame.length;int col = frame[0].length;int[][] dp = new int[row][col];dp[0][0] = frame[0][0];// dp[i][j] 代表到 i,j 的最大珠宝值// 1 3 1// 1 5 1// 4 2 1for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {dp[i][j] = frame[i][j];if (i - 1 >= 0) {dp[i][j] = dp[i - 1][j] + frame[i][j];}if (j - 1 >= 0) {dp[i][j] = Math.max(dp[i][j], dp[i][j - 1] + frame[i][j]);}}}return dp[row - 1][col - 1];}
}

68. LCR 185. 统计结果概率

这道题,可以去看看大佬的题解。

代码实现:

class Solution {public double[] statisticsProbability(int num) {// prev 表示 n - 1 个骰子点数double[] prev = {1 / 6d, 1 / 6d, 1 / 6d, 1 / 6d, 1 / 6d, 1 / 6d};for (int i = 2; i <= num; i++) {// 第 n 个骰子点数double[] cur = new double[5 * i + 1];// [n, 6n] -> 5*n + 1for (int j = 0; j < prev.length; j++) {// 每个骰子有 6 点// 第 n 个骰子点数 = 第 n-1 个骰子点数 + 当前骰子点数for (int k = 0; k < 6; k++) {cur[j + k] += prev[j] * 1 / 6;}}prev = cur;}return prev;}
}

69. LCR 187. 破冰游戏

约瑟夫环问题,dp[i] = (dp[i -1] + target) % num.

代码实现:

class Solution {public int iceBreakingGame(int num, int target) {// 用动态规划// dp[i] = (dp[i - 1] + target) % num// dp[i] 表示以 i 个成员为约瑟夫环,最后剩下的成员编号int dp = 0;for (int i = 2; i <= num; i++) {dp = (dp + target) % i;}return dp;}
}

70. LCR 129. 字母迷宫

这种找路径的问题,一般用深搜来做,因为图中的每个节点都可能是单词开头,所以需要遍历图,然后对图中的每个节点进行深搜即可。

代码实现:

class Solution {public boolean wordPuzzle(char[][] grid, String target) {int row = grid.length;int col = grid[0].length;char[] arr = target.toCharArray();// 遍历图for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {boolean[][] flg = new boolean[row][col];// 对每个节点进行深搜if (dfs(grid, flg, i, j, row, col, arr, 0)) {return true;}}}return false;}public boolean dfs(char[][] arr, boolean[][] flg, int i, int j, int row, int col, char[] target, int k) {// 越界或者已经访问过或者对应的字符不一致,则返回 falseif (i < 0 || i >= row || j < 0 || j >= col || flg[i][j] || arr[i][j] != target[k]) {return false;}// 标记遍历过flg[i][j] = true;if (k == target.length - 1) {return true;}// 往四个方向继续boolean ans = dfs(arr, flg, i - 1, j, row, col, target, k + 1)|| dfs(arr, flg, i + 1, j, row, col, target, k + 1)|| dfs(arr, flg, i, j - 1, row, col, target, k + 1)|| dfs(arr, flg, i, j + 1, row, col, target, k + 1);// 回溯flg[i][j] = false;return ans;}
}

71. LCR 130. 衣橱整理

可以用深搜来做。

代码实现:

class Solution {public int wardrobeFinishing(int m, int n, int cnt) {boolean[][] flg = new boolean[m][n];return dfs(m, n, 0, 0, flg, cnt);}public int dfs(int m, int n, int i, int j, boolean[][] flg, int cnt) {// 判断越界以及是否遍历过以及是否符合整理要求if (i < 0 || i >= m || j < 0 || j >= n || flg[i][j] || (numSum(i) + numSum(j) > cnt)) {return 0;}// 标记一下flg[i][j] = true;return dfs(m, n, i, j + 1, flg, cnt) + dfs(m, n, i + 1, j, flg, cnt) + 1;}public int numSum(int num) {int sum = 0;while (num != 0) {sum += num % 10;num /= 10;}return sum;}
}

72. LCR 146. 螺旋遍历二维数组

代码实现:

class Solution {public int[] spiralArray(int[][] array) {if (array.length == 0)return new int[0];int x1 = 0, y1 = 0;int x2 = array.length - 1, y2 = array[0].length - 1;int k = 0;int[] ret = new int[(x2 + 1) * (y2 + 1)];while (x1 <= x2 && y1 <= y2) {// 第一行for (int i = y1; i <= y2; i++) {ret[k++] = array[x1][i];}// 最后一列for (int i = x1 + 1; i <= x2; i++) {ret[k++] = array[i][y2];}// 最后一行if (x1 < x2) {for (int i = y2 - 1; i >= y1; i--) {ret[k++] = array[x2][i];}}// 第一列if (y1 < y2) {for (int i = x2 - 1; i > x1; i--) {ret[k++] = array[i][y1];}}x1++;y1++;x2--;y2--;}return ret;}
}

贪心算法

73. LCR 188. 买卖芯片的最佳时机

让你求最大值,第一眼就是两层遍历搞定。

但是还有另一种方法,要想获得利润最大值,一般是低买高卖,低价买入高价卖出,所以我们可以定义一个变量 minPrice 记录股票的最小值,再定义一个 max 来记录最大利润,只要当前股票 - minPrice 比 max 大,max 就更新。最后返回 max 即可。

代码实现:

class Solution {public int bestTiming(int[] prices) {int max = 0;for (int i = 0; i < prices.length - 1; i++) {for (int j = i + 1; j < prices.length; j++) {int tmp = prices[j] - prices[i];if (tmp > max) {max = tmp;}}}return max;}
}class Solution {public int bestTiming(int[] prices) {int max = 0;// 记录最低股票值int minPrice = Integer.MAX_VALUE;// 低买高卖for (int i = 0; i < prices.length; i++) {if (prices[i] < minPrice) {minPrice = prices[i];}if (prices[i] - minPrice > max) {max = prices[i] - minPrice;}}return max;}
}

找规律

74. LCR 162. 数字 1 的个数

可以去看看大佬的题解。

代码实现:

class Solution {public int digitOneInNumber(int num) {int digit = 1, count = 0;int high = num / 10, cur = num % 10, low = 0;while (high != 0 || cur != 0) {// 当 cur 和高位都是 0,则说明已经遍历完该数字了if (cur == 0) {// 当前位是 0count += high * digit;} else if (cur == 1) {// 当前位是 1count += high * digit + low + 1;} else {count += (high + 1) * digit;}// 1   2   3   4//  high  cur lowlow += cur * digit;cur = high % 10;// 为 high 的最后一位high /= 10;digit *= 10;}return count;}
}

75. LCR 163. 找到第 k 位数字

可以去看看大佬题解。

代码实现:

class Solution {public int findKthNumber(int k) {// 几位数int digit = 1;// 从哪里开始long start = 1;// digit 位数一共有几个long count = 9;// 获取第 k 位数 是几位数while (k > count) {k -= count;digit++;start *= 10;count = 9 * start * digit;}// 确定 k 所在的数字// start +  (k - 1) / digit 用来计算从 start 开始跳过多少个完整的数字long num = start + (k - 1) / digit;return Long.toString(num).charAt((k - 1) % digit) - '0';}
}

相关文章:

剑指 offer 刷题集

目录 数组 1. LCR 121. 寻找目标值 - 二维数组 2. LCR 120. 寻找文件副本 3. LCR 128. 库存管理 I 4. LCR 131. 砍竹子 I 5. LCR 132. 砍竹子 II 6. LCR 135. 报数 7. LCR 139. 训练计划 I 8. LCR 158. 库存管理 II 9. LCR 159. 库存管理 III 10. LCR 160. 数据流中…...

C++在线开发环境搭建(WEBIDE)

C在线开发环境搭建 一、环境说明1.1 系统基础环境说明1.1 docker-ce社区版安装 二、codeserver构建2.1 构建codeserver环境的docker容器2.2 构建docker镜像2.3 运行docker2.4 运行展示 三、构建codeserver中的c开发环境3.1 插件下载3.2 插件安装 四、其他知识4.2 code-server配…...

重磅首发!大语言模型LLM学习路线图来了!

ChatGPT的出现在全球掀起了AI大模型的浪潮&#xff0c;2023年可以被称为AI元年&#xff0c;AI大模型以一种野蛮的方式&#xff0c;闯入你我的生活之中。 从问答对话到辅助编程&#xff0c;从图画解析到自主创作&#xff0c;AI所展现出来的能力&#xff0c;超出了多数人的预料&…...

neo4j关系的创建删除 图的删除

关系的创建和删除 关系创建 CREATE (:Person {name:"jack"})-[:LOVE]->(:Person {name:"Rose"})已有这个关系时&#xff0c;merge不起效果 MERGE (:Person {name:"Jack" })-[:LOVE]->(:Person {name:"Rose"})关系兼顾节点和关…...

【WRF运行第三期】服务器上运行WRF模型(官网案例-Hurricane Matthew)

【WRF运行第三期】运行WRF模型&#xff08;官网案例-Hurricane Matthew&#xff09; 官网案例-Hurricane Matthew介绍0 创建DATA文件夹1 WPS预处理1.1 解压GRIB数据&#xff08;ungrib.exe&#xff09;1.1.1 解压GRIB数据---GFS&#xff08;Matthew案例研究数据&#xff09;1.1…...

基于springboot的书店图书销售管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于springboot的书店图书销售管理系统拥有三个角色 管理员&#xff1a;用户管理、角色管理、权限管理、店铺管理等商家&#xff1a;图书管理、上架图书、访问量统计、销售总额统计、订单…...

Spring MVC 基本配置步骤 总结

1.简介 本文记录Spring MVC基本项目拉起配置步骤。 2.步骤 在pom.xml中导入依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.0.6</version><scope>…...

HCIP--以太网交换安全(一)

以太网交换安全概述&#xff1a;以太网交换安全是一系列技术和策略的集合&#xff0c;旨在保护以太网交换机免受各种网络攻击和威胁。 端口隔离 一、端口隔离概述&#xff1a; 作用&#xff1a;可以实现同一个VLAN内端口的隔离 优势&#xff1a; 端口隔离功能为用户提供了更…...

PyQt5中关于QLineEdit的空输入报错的简单处理

PyQt5中关于QLineEdit的空输入报错的简单处理 前言分析原因解决办法总结 前言 在PyQt5的界面中对于数据的输入&#xff0c;最常用的就是QLineEdit控件&#xff0c;该控件作为基本的数据输入控件已经能满足我们的简单使用。在使用过程&#xff0c;出现闪退情况&#xff0c;发现…...

【前端】ES12:ES12新特性

文章目录 1 逻辑赋值操作符2 数字分隔符3 replaceAll4 Promise.any5 WeakRef6 FinalizationRegistry 1 逻辑赋值操作符 逻辑赋值操作符 ??、&&、 ||。 let a true let b false //a && b //false a || b ; //true console.log(a)let obj {name:"ker…...

语音识别(非实时)

1.环境 python &#xff1a;3.10.14 2.完整代码 import whisper #whisper import wave # 使用wave库可读、写wav类型的音频文件 import pyaudio # 使用pyaudio库可以进行录音&#xff0c;播放&#xff0c;生成wav文件 def record(time): # 录音程序# 定义数据流块CHUNK …...

【计算机网络】--URL统一资源定位符

一个网站地址实例 scheme://host.domain:port/path/filename scheme——定义因特网服务的类型&#xff0c;常见的类型是http host——定义域主机&#xff08;http的默认主机是www&#xff09; domain———定义因特网的域名&#xff0c;例如&#xff0c;jinyun.fun &#xf…...

在成都建“圈”五年,鲲鹏让智能化新风吹遍巴蜀大地

科技圈里流行着“互联网四大中心”的说法&#xff0c;即南边的深圳、东边的杭州、北边的北京和西边的成都。 深圳、杭州、北京几乎没有太大的争议&#xff0c;这里是国内著名的互联网公司聚集地&#xff0c;有着国内排行前三的互联网企业总部&#xff0c;单单一个北京西二旗就…...

Unity图形用户界面!*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。(万字解析)

Unity 3D GUI 简介 游戏开发过程中&#xff0c;开发人员往往会通过制作大量的图形用户界面&#xff08; Graphical User Interface&#xff0c;GUI &#xff09;来增强游戏与玩家的交互性。 Unity 3D 中的图形系统分为 OnGUI、NGUI、UGUI等&#xff0c;这些类型的图形系统内容…...

【JAVA报错已解决】Java.lang.NullPointerException

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…...

JSON 教程

JSON 教程 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head> …...

HBase 的基本架构 详解

HBase 是一个分布式的、面向列的数据库&#xff0c;构建在 HDFS&#xff08;Hadoop Distributed File System&#xff09;之上&#xff0c;提供高效的随机读写操作。为了全面理解 HBase 的基础架构&#xff0c;需要从逻辑架构、物理存储、组件之间的交互、数据管理和底层设计出…...

crypt.h:No such file or directory报错处理

crypt.h&#xff1a;No such file or directory 报错处理 前言&#xff1a;本文初编辑于2024年9月27日 CSDN主页&#xff1a;https://blog.csdn.net/rvdgdsva 博客园主页&#xff1a;https://www.cnblogs.com/hassle 博客园本文链接&#xff1a; 大&#xff01;萌&#xff0…...

网络消费维权的9个常见法律问题

一、忘记付尾款&#xff0c;定金能否退还&#xff1f; 不能。消费者在网络提交订单后&#xff0c;合同即成立。合同成立后&#xff0c;消费者的义务为按时付款。若消费者在支付定金后未能支付尾款&#xff0c;即未能履行付款义务&#xff0c;会导致合同无法履行&#xff0c;构…...

detectron2是怎么建立模型的?以SparseInst代码为例

看SparseInst论文发现论文里有些地方没讲清楚&#xff1b;遂找SparseInst源码来看模型结构 我选择从推理代码来找模型结构&#xff1a; 经探索&#xff0c;在SparseInst代码里&#xff0c;推理需要执行代码 python demo.py --config-file configs/sparse_inst_r50_base.yaml …...

kafka监控平台Kafdrop:使用记录

背景 AI的发展真是太方便了&#xff0c;让它给我推荐一款轻量级&#xff0c;没有学习曲线的kafka监控平台&#xff0c;它就给我推荐这一款。用了一下果然没有一点学习曲线。 目前已经满足了我的需求&#xff0c;可视化界面&#xff0c;topic、消息、消费者group信息以及消费情…...

的使用和内联函数

今天我们来了解一下C中的&和内联函数 引用标识符& C觉得C语言部分的指针有些麻烦&#xff0c;容易混乱&#xff0c;所以C创造了一个标识符&&#xff0c;表示是谁的别名。跟指针对比一下&#xff1a;int* a1&b1;int &a2b2;这样看&#xff0c;显然a1存放的…...

征程6 上基于 DEB 工具实现包管理

1.引言 在开发、调测过程中&#xff0c;开发人员需要将系统软件、应用软件部署到 Soc 板端&#xff0c;以用于运行调试。传统的部署方式是通过解压复制或者调用部署脚本。这样的部署方式需要有着方式不统一、维护投入大的缺点。 在 linux 系统上&#xff0c;大多采用包管理的…...

【git】一文详解: git rebase到底有啥问题

引子 我反复看到这样的评论&#xff1a;“git rebase 像屎一样”。人们似乎对此有很强烈的感受&#xff0c;我真的很惊讶&#xff0c;因为我没有遇到太多使用 rebase 的问题&#xff0c;而且我一直在使用它。 使用 rebase 的成本有多大&#xff1f;在实际使用中它给你带来了什…...

高性能计算应用优化实践之WRF

WRF&#xff08;Weather Research Forecast&#xff09;模式是由美国国家大气研究中心&#xff08;NCAR&#xff09;、国家环境预报中心&#xff08;NCEP&#xff09;等机构自1997年起联合开发的新一代高分辨率中尺度天气研究预报模式&#xff0c;重点解决分辨率为1&#xff5e…...

nsight-compute使用教程

一 安装 有的时候在linux上安装上了nsight-compute,可以生成报告,但是却因为缺少qt组件而无法打开,我选择的方法是在linux上生成报告,在window上的nsight compute的图形界面打开,需要注意的是,nsight compute图形界面的版本一定要更高,不然无法打开 二 使用 2.1 生成…...

【深度学习】03-神经网络01-4 神经网络的pytorch搭建和参数计算

# 计算模型参数,查看模型结构,我们要查看有多少参数&#xff0c;需要先安装包 pip install torchsummary import torch import torch.nn as nn from torchsummary import summary # 导入 summary 函数&#xff0c;用于计算模型参数和查看模型结构# 创建神经网络模型类 class Mo…...

我与Linux的爱恋:命令行参数|环境变量

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 一.命令行参数二.环境变量1.环境变量的基本概念2.查看环境变量的方法3.环境变量相关命令4.环境变量的组织方式以及获取环境变量的三种方法 环境变量具有全局属性 一…...

django drf 统一Response格式

场景 需要将响应体按照格式规范返回给前端。 例如&#xff1a; 响应体中包含以下字段&#xff1a; {"result": true,"data": {},"code": 200,"message": "ok","request_id": "20cadfe4-51cd-42f6-af81-0…...

SM2协同签名算法中随机数K的随机性对算法安全的影响

前面介绍过若持有私钥d的用户两次SM2签名过程中随机数k相同&#xff0c;在对手获得两次签名结果Sig1和Sig2的情况下&#xff0c;可破解私钥d。 具体见SM2签名算法中随机数K的随机性对算法安全的影响_sm2关闭随机数-CSDN博客 另关于SM2协同签名过程&#xff0c;具体见SM2协同签…...