面试必刷101 Java题解 -- part 1
练习地址
面试必刷101-牛客
- 1、链表反转
- 2、链表内指定区间反转
- **3. 链表中的节点每k个一组翻转**
- 4、**合并两个排序的链表**
- 5、**合并k个已排序的链表**
- 6、**判断链表中是否有环**
- **7、链表中环的入口结点**
- 8、链表中倒数最后k个结点
- **9、删除链表的倒数第n个节点**
- **10、两个链表的第一个公共结点**
- **11、链表相加(二)**
- 12、两数相加
- 13、字符串相加
- 14、二进制求和
- 15、36进制相加
- **16、单链表的排序**
- **17、判断一个链表是否为回文结构**
- **18、判断是否为回文字符串**
- 19、最长回文字符串
- **20、链表的奇偶重排**
- **21、删除有序链表中重复的元素-I**
- **22、删除有序链表中重复的元素-II**
- 23、二分查找-I
- 循环结束条件总结
- **24、二维数组中的查找**
- **25、寻找峰值**
- **24、数组中的逆序对**
- 25、旋转数组的最小数字
- 26、比较版本号
- **27、二叉树的前序遍历**
- **28、二叉树的中序遍历**
- 29、二叉树的后序遍历
- **30、求二叉树的层序遍历**
- **31、按之字形顺序打印二叉树**
- 32、二叉树的最大深度
- **33、二叉树中和为某一值的路径(一)**
- **34、二叉搜索树与双向链表**
- 35、**对称的二叉树**
- **36、合并二叉树**
- 37、**二叉树的镜像**
- **38、判断是不是二叉搜索树**
- **39、判断是不是完全二叉树**
- **40、判断是不是平衡二叉树**
- 41、**二叉搜索树的最近公共祖先**
- **42、在二叉树中找到两个节点的最近公共祖先**
- **43、序列化二叉树**
- **44、重建二叉树**
- **45、输出二叉树的右视图**
1、链表反转
/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class Solution {public ListNode ReverseList(ListNode head) {ListNode last = null;ListNode next = null;while(head != null){next = head.next;head.next = last;//反转last = head;//更新装态head = next;}return last;}
}
2、链表内指定区间反转
import java.util.*;public class Solution {public ListNode reverseBetween (ListNode head, int m, int n) {// write code hereListNode dummy = new ListNode(-1);dummy.next = head;ListNode left = dummy;ListNode right = dummy;//走到m的前一个位置for (int i = 0; i < m - 1; i++) {left = left.next;}right = left;ListNode start = left.next;//right要走到n的位置上for (int i = 0; i < n - m + 1; i++) {right = right.next;}ListNode next = right.next;//将n处的next置空right.next = null;left.next = reverse(start);//修正startstart.next = next;return dummy.next;}public ListNode reverse(ListNode head) {ListNode last = null;ListNode next = null;while (head != null) {next = head.next;head.next = last;last = head;head = next;}return last;}
}
3. 链表中的节点每k个一组翻转
public class Solution {/**** @param head ListNode类* @param k int整型* @return ListNode类*/public ListNode reverseKGroup (ListNode head, int k) {// write code hereListNode dummy = new ListNode(-1);dummy.next = head;ListNode left = dummy;ListNode right = dummy;while (right != null) {for (int i = 0; i < k ; i++) {right = right.next;if (right == null) return dummy.next;}ListNode start = left.next;ListNode next = right.next;right.next = null;//指向反转后的结点left.next = myrevser(start);//修正指针错误start.next = next;//重新指向下一个k分组的前一个节点left = start;right = left;}return dummy.next;}public ListNode myrevser(ListNode head) {ListNode last = null;ListNode next = null;while (head != null) {next = head.next;head.next = last;last = head;head = next;}return last;}
}
4、合并两个排序的链表
/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class Solution {public ListNode Merge(ListNode list1, ListNode list2) {if (list1 == null) return list2;if (list2 == null) return list1;ListNode help = new ListNode(Integer.MIN_VALUE);ListNode cur = help;while (list1 != null && list2 != null) {if (list1.val <= list2.val) {cur.next = list1;list1 = list1.next;} else {cur.next = list2;list2 = list2.next;}cur = cur.next;}cur.next = list1 == null ? list2 : list1;return help.next;}
}
5、合并k个已排序的链表
import java.util.*;
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/
public class Solution {public ListNode mergeKLists(ArrayList<ListNode> lists) {return merger(lists, 0, lists.size() - 1);}public ListNode merger(ArrayList<ListNode> lists, int l, int r) {if (l == r) return lists.get(l);if (l > r) return null;int mid = (l + r) >> 1;ListNode leftmerge = merger(lists, l, mid);ListNode rightmerge = merger(lists, mid + 1, r);return mergerTowList(leftmerge, rightmerge);}public ListNode mergerTowList(ListNode left,ListNode right){if (left == null) return right;if (right == null) return left;ListNode help = new ListNode(Integer.MIN_VALUE);ListNode cur = help;while(left != null && right != null){if(left.val <= right.val){cur.next = left;left = left.next;}else{cur.next = right;right = right.next;}cur = cur.next;}cur.next = left == null ? right : left;return help.next;}
}
6、判断链表中是否有环
public class Solution {public boolean hasCycle(ListNode head) {if(head == null) return false;ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(slow == fast) return true;}return false;}
}
使用两个指针,fast\textit{fast}fast 与 slow\textit{slow}slow。它们起始都位于链表的头部。随后,slow\textit{slow}slow指针每次向后移动一个位置,而 fast\textit{fast}fast指针向后移动两个位置。如果链表中存在环,则 fast\textit{fast}fast指针最终将再次与 slow\textit{slow}slow指针在环中相遇。
7、链表中环的入口结点
使用两个指针,fast\textit{fast}fast 与slow\textit{slow}slow。它们起始都位于链表的头部。随后,slow\textit{slow}slow指针每次向后移动一个位置,而 fast\textit{fast}fast指针向后移动两个位置。如果链表中存在环,则 fast\textit{fast}fast指针最终将再次与slow\textit{slow}slow指针在环中相遇。当发现fast\textit{fast}fast 与slow\textit{slow}slow相遇时,将fast\textit{fast}fast指向链表头部;随后,它和slow\textit{slow}slow每次向后移动一个位置。最终,它们会在入环点相遇。
public class Solution {public ListNode EntryNodeOfLoop(ListNode pHead) {if(pHead == null) return null;ListNode fast = pHead;ListNode slow = pHead;while(fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;if(slow == fast){fast = pHead;while(fast != slow){fast = fast.next;slow = slow.next;}return fast;}}return null;}
}
8、链表中倒数最后k个结点
- 使用双指针则可以不用统计链表长度。
public ListNode FindKthToTail (ListNode pHead, int k) {// write code hereListNode fast = pHead;ListNode slow = pHead;for (int i = 0; i < k; i++) {if(fast == null) return null;fast = fast.next;}while (fast != null) {fast = fast.next;slow = slow.next;}return slow;}
9、删除链表的倒数第n个节点
public ListNode removeNthFromEnd (ListNode head, int n) {// write code hereListNode dummy = new ListNode(-1);dummy.next = head;ListNode fast = head;ListNode slow = dummy; //将slow位置提前for (int i = 0; i < n ; i++) {//快慢指针,走到第n个节点的前一个fast = fast.next;}while (fast != null) {fast = fast.next;slow = slow.next;}slow.next = slow.next.next;return dummy.next;}
10、两个链表的第一个公共结点
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {int length = 0; // pHead1 - pHead2长度之差if (pHead1 == null || pHead2 == null) return null;ListNode cur1 = pHead1;ListNode cur2 = pHead2;while (cur1 != null) {cur1 = cur1.next;length++;}while (cur2 != null) {cur2 = cur2.next;length--;}// 尾端节点不一致判断没有节点if (cur1 != cur2) return null;// cur1表示长的那个链表cur1 = length > 0 ? pHead1 : pHead2;cur2 = cur1 == pHead1 ? pHead2 : pHead1;length = Math.abs(length);// 长链表走length步for (int i = 0; i < length; i++) {cur1 = cur1.next;}// 两个链表同时走直到相遇while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;}
11、链表相加(二)
本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,我们可以使用栈:把所有数字压入栈中,再依次取出相加。计算过程中需要注意进位的情况。
public ListNode addInList (ListNode head1, ListNode head2) {// write code hereStack<Integer> s1 = new Stack<>();Stack<Integer> s2 = new Stack<>();//将链表中数据放入栈中while (head1 != null) {s1.push(head1.val);head1 = head1.next;}while (head2 != null) {s2.push(head2.val);head2 = head2.next;}ListNode res = null; //返回的结果int carry = 0; //进位// 栈不为空或者存在进位时while (!s1.isEmpty() || !s2.isEmpty() || carry != 0) {int val1 = s1.isEmpty() ? 0 : s1.pop();int val2 = s2.isEmpty() ? 0 : s2.pop();int sum = val1 + val2 + carry;carry = sum / 10; // 更新进位int cur = sum % 10; // 个位数字ListNode curNode = new ListNode(cur);//更新结果并连线curNode.next = res;res = curNode;}return res;}
12、两数相加
本题低位在前高位在后,可以直接从头开始相加
public ListNode addTwoNumbers(ListNode head1, ListNode head2) {// write code hereListNode res = new ListNode(0); //返回的结果ListNode help = res;int carry = 0; //进位// 栈不为空或者存在进位时while (head1!=null || head2!=null || carry != 0) {int val1 = head1==null ? 0 : head1.val;int val2 = head2==null ? 0 : head2.val;int sum = val1 + val2 + carry;carry = sum / 10; // 更新进位int cur = sum % 10; // 个位数字help.next = new ListNode(cur);help = help.next;if(head1!=null) head1 = head1.next;if(head2!=null) head2 = head2.next;}return res.next;}
13、字符串相加
public String addStrings(String num1, String num2) {StringBuilder res = new StringBuilder("");int num1Length = num1.length() - 1;int num2Length = num2.length() - 1;int carry = 0;//进位while (num1Length >= 0 || num2Length >= 0 || carry != 0) {int n1 = num1Length >= 0 ? num1.charAt(num1Length) - '0' : 0;int n2 = num2Length >= 0 ? num2.charAt(num2Length) - '0' : 0;int sum = n1 + n2 + carry;carry = sum / 10; //更新进位int cur = sum % 10; //个位上数字res.append(cur);num1Length--;num2Length--;}return res.reverse().toString();}
14、二进制求和
class Solution {public String addBinary(String a, String b) {StringBuilder ans = new StringBuilder();int alength = a.length() - 1;int blength = b.length() - 1;int carry = 0;//进位while(alength >= 0 || blength >= 0 || carry != 0){int n1 = alength >= 0? a.charAt(alength) - '0':0;int n2 = blength >= 0? b.charAt(blength) - '0':0;int sum = n1 + n2 + carry;int cur = sum % 2;carry = sum / 2; //更新进位ans.append(cur);alength--;blength--;}return ans.reverse().toString();}
}
15、36进制相加
题目
实现一个 36 进制的加法 0-9 a-z。
示例
输入:[“abbbb”,“1”],输出:“abbbc”
String add36Strings(String num1, String num2) {int carry = 0;int i = num1.length() - 1, j = num2.length() - 1;StringBuilder sb = new StringBuilder();while (i >= 0 || j >= 0 || carry != 0) {int x = i >= 0 ? getInt(num1.charAt(i)) : 0;int y = j >= 0 ? getInt(num2.charAt(j)) : 0;int sum = x + y + carry; //本次结果sb.append(getChar(sum % 36));carry = sum / 36; //进位i--;j--;}//翻转return sb.reverse().toString();}private int getInt(char i) {if (i >= '0' && i <= '9') {return i - '0';} else {return i - 'a' + 10;}}private char getChar(int i) {if (i <= 9) {return (char) (i + '0');} else {return (char) (i - 10 + 'a');}}
16、单链表的排序
对于链表最适合的是归并排序
public class Solution {/**** @param head ListNode类 the head node* @return ListNode类*/public ListNode sortInList (ListNode head) {// write code here// 对于链表最适合的是归并排序if(head == null) return null;return sortPartList(head);}public ListNode sortPartList(ListNode head) {if (head.next == null) return head; //链表只有一个节点// 获取 mid -- 中点为slowListNode fast = head, slow = head;ListNode pre = null;//中点的前一个节点while (fast != null && fast.next != null) {pre = slow;slow = slow.next;fast = fast.next.next;}pre.next = null; //断开拆成两个链表ListNode leftNode = sortPartList(head);ListNode rightNode = sortPartList(slow);return merge(leftNode, rightNode);}public ListNode merge(ListNode left, ListNode right) {ListNode dummy = new ListNode(0);ListNode help = dummy;while (left != null && right != null) {if (left.val <= right.val) {help.next = left;left = left.next;} else {help.next = right;right = right.next;}help = help.next;}help.next = left == null ? right : left;return dummy.next;}
}
快速方法
public ListNode sortInList (ListNode head) {// write code here//小根堆Queue<ListNode> queue = new PriorityQueue<>((o1, o2) -> o1.val - o2.val);ListNode help = new ListNode(0);ListNode temp = help;while(head != null){queue.add(head);head = head.next;}while(!queue.isEmpty()){ListNode node = queue.poll();node.next = null;//将节点next置空temp.next = node;temp = temp.next;//更新}return help.next;}
17、判断一个链表是否为回文结构
利用快慢指针找到中点,将后半截反序,两个指针从两边遍历到中点,逐个比较
当慢指针走到中点时,将其下一个指针赋值为null,同时将后面的指针指向中点,然后遍历,返回true/false,然后在将后面的指针改回去
public boolean isPail (ListNode head) {// write code hereListNode fast = head, slow = head;while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;}// 中点即为slowslow = reverse(slow);fast = head;while (slow != null) {if (slow.val != fast.val) return false;slow = slow.next;fast = fast.next;}return true;}public ListNode reverse(ListNode head) {ListNode last = null;ListNode next = null;while (head != null) {next = head.next;head.next = last;//reverselast = head;head = next;}return last;}
18、判断是否为回文字符串
import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** @param str string字符串 待判断的字符串* @return bool布尔型*/public boolean judge (String str) {// write code hereint l = 0;int r = str.length() - 1;while (l < r) {if (str.charAt(l) != str.charAt(r)) return false;l++;r--;}return true;}
}
19、最长回文字符串
- step 1:遍历字符串每个字符。
- step 2:以每次遍历到的字符为中心(分奇数长度和偶数长度两种情况),不断向两边扩展。
- step 3:如果两边都是相同的就是回文,不断扩大到最大长度即是以这个字符(或偶数两个)为中心的最长回文子串。
- step 4:我们比较完每个字符为中心的最长回文子串,取最大值即可。
import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param A string字符串* @return int整型*/public int getLongestPalindrome (String A) {// write code hereint res = 1;for (int i = 0; i < A.length() - 1; i++) {//分为奇数和偶数两种情况res = Math.max(res, Math.max(helper(A, i, i), helper(A, i, i + 1)));}return res;}public int helper(String A, int begin, int end) {//每个中心点开始扩展while (begin >= 0 && end < A.length() && A.charAt(begin) == A.charAt(end)) {begin--;end++;}//返回长度return end - begin - 1;}
}
20、链表的奇偶重排
先一个左正蹬,把奇数节点串一块儿,再一个右鞭腿,把偶数节点串一起,然后啪,很快啊,把两个连成一条链表,可以说是训练有素,有bear来了
public ListNode oddEvenList (ListNode head) {// write code hereif(head == null) return head;ListNode odd = head;//奇数ListNode even = head.next, evenHead = even; //偶数while(even != null && even.next != null){odd.next = even.next;odd = odd.next;even.next = odd.next;even = even.next;}odd.next = evenHead;return head;//奇数头是head}
21、删除有序链表中重复的元素-I
import java.util.*;
public class Solution {public ListNode deleteDuplicates (ListNode head) {//一次遍历//空链表if(head == null) return null;//遍历指针ListNode cur = head; //指针当前和下一位不为空while(cur != null && cur.next != null){ //如果当前与下一位相等则忽略下一位if(cur.val == cur.next.val) cur.next = cur.next.next;//否则指针正常遍历else cur = cur.next;}return head;}
}
22、删除有序链表中重复的元素-II
删除重复元素,只要重复就全部给删除(一个也不留)
import java.util.*;
public class Solution {public ListNode deleteDuplicates (ListNode head) {//空链表if(head == null) return null;ListNode dummy = new ListNode(0);//在链表前加一个表头dummy.next = head;ListNode helper = dummy;while(helper.next != null && helper.next.next != null){//遇到相邻两个节点值相同if(helper.next.val == helper.next.next.val){int temp = helper.next.val;//将所有相同的都跳过while (helper.next != null && helper.next.val == temp)helper.next = helper.next.next;//忽略下一位}elsehelper = helper.next;}//返回时去掉表头return dummy.next;}
}
23、二分查找-I
public int search (int[] nums, int target) {// write code hereint left = 0, right = nums.length - 1 ;while (left <= right) {int mid = left + (right - left) / 2;int num = nums[mid];if (num == target) return mid;else if (num > target) right = mid - 1;else left = mid + 1;}return -1;
}
循环结束条件总结
情况一
如果搜索区间[left, right]中一定有目标值索引,那么循环截止条件是while(left < right)
情况二
如果搜索区间[left, right]中不一定有目标值索引,那么循环截止条件是while(left <= right);(一般用于搜索区间内是否有某个值)
24、二维数组中的查找
首先看四个角,左上与右下必定为最小值与最大值,而左下与右上就有规律了:左下元素大于它上方的元素,小于它右方的元素,右上元素与之相反。既然左下角元素有这么一种规律,相当于将要查找的部分分成了一个大区间和小区间,每次与左下角元素比较,我们就知道目标值应该在哪部分中,于是可以利用分治思维来做。
具体做法:
- step 1:首先获取矩阵的两个边长,判断特殊情况。
- step 2:首先以左下角为起点,若是它小于目标元素,则往右移动去找大的,若是他大于目标元素,则往上移动去找小的。
- step 3:若是移动到了矩阵边界也没找到,说明矩阵中不存在目标值。
public class Solution {public boolean Find(int target, int [][] array) {int r = array.length - 1;int c = 0;while(r >= 0 && c < array[0].length){int cmp = array[r][c];if(cmp == target) return true;else if(cmp > target) r--;else c++;}return false;}
}
25、寻找峰值
public class Solution {public int findPeakElement (int[] nums) {// write code hereint left = 0;int right = nums.length - 1;int mid;while (left < right) {// 找到中间值mid = (left + right) >> 1;// 只要当前中间值 大于它的下一位,说明当前处于下坡状态,那么往数组的左边遍历,就可以找到峰值if(nums[mid] > nums[mid + 1])// 因为mid 比 它下一位大,所以当前mid有可能是山峰,这里向左遍历的时候需要把mid包含在内right = mid; else // 否则当前中间值小于等于它的下一位时,说明山峰处于上坡状态,向右查找就可以找到峰值// 因为mid小于它的下一位,所以这里将left赋值为mid+1,从大的那个数开始向右查找left = mid + 1;}// 此时left 和 right相等时 上面的while退出// 最终返回 left 或 right都可以return right;}
}
24、数组中的逆序对
public class Solution {public int InversePairs(int [] array) {//归并算法//计数条件是左边大于右边if (array == null || array.length < 2) return 0;return (int)process(array, 0, array.length - 1) % 1000000007;}public long process(int [] array, int left, int right) {if (left >= right) return 0;int mid = left + (right - left) / 2;long leftnum = process(array, left, mid);//左边排好序long rightnum = process(array, mid + 1, right);//右边排好序long mergernum = merge(array, left, mid,right); //利用外排序将左右两边排好序return leftnum + rightnum + mergernum;}public long merge(int [] array, int left, int mid, int right) {int[] help = new int[right - left + 1];int helpIndex = 0;//外排索引int count = 0;//逆序对数量int leftHead = left;//左边头索引int rightHead = mid + 1;//右边头索引while (leftHead <= mid && rightHead <= right) {if (array[leftHead] <= array[rightHead]) {help[helpIndex++] = array[leftHead++];} else {help[helpIndex++] = array[rightHead++];count = count + mid - leftHead + 1;}}while (leftHead <= mid) {help[helpIndex++] = array[leftHead++];}while (rightHead <= right) {help[helpIndex++] = array[rightHead++];}//覆盖回去for (int i = 0; i < help.length; i++) {array[left + i] = help[i];}return count % 1000000007;}
}
25、旋转数组的最小数字
思路:
旋转数组将原本有序的数组分成了两部分有序的数组,因为在原始有序数组中,最小的元素一定是在首位,旋转后无序的点就是最小的数字。我们可以将旋转前的前半段命名为A,旋转后的前半段命名为B,旋转数组即将AB变成了BA,我们想知道最小的元素到底在哪里。
因为A部分和B部分都是各自有序的,所以我们还是想用分治来试试,每次比较中间值,确认目标值(最小元素)所在的区间。
具体做法:
- step 1:双指针指向旋转后数组的首尾,作为区间端点。
- step 2:若是区间中点值大于区间右界值,则最小的数字一定在中点右边。
- step 3:若是区间中点值等于区间右界值,则是不容易分辨最小数字在哪半个区间,比如[1,1,1,0,1],应该逐个缩减右界。
- step 4:若是区间中点值小于区间右界值,则最小的数字一定在中点左边。
- step 5:通过调整区间最后即可锁定最小值所在。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMA7sX5G-1677307640258)(${img}/image-20230112124909276.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b3jz71xM-1677307640258)(${img}/image-20230112125112145.png)]
public int minNumberInRotateArray(int [] array) {int left = 0, right = array.length - 1 ;while (left < right) {int mid = left + (right - left) / 2;//区间中点值大于区间右界值,则最小的数字一定在中点右边。//array[right] 是右边界if (array[mid] > array[right]) left = mid + 1;//区间中点值小于区间右界值,则最小的数字一定在中点左边。else if (array[mid] < array[right]) right = mid;else right--;//无法判断在哪一边 区间中点值等于区间右界值,则是不容易分辨最小数字在哪半个区间,比如[1,1,1,0,1],应该逐个缩减右界。}return array[left];
}
26、比较版本号
具体做法:
- step 1:利用两个指针表示字符串的下标,分别遍历两个字符串。
- step 2:每次截取点之前的数字字符组成数字,即在遇到一个点之前,直接取数字,加在前面数字乘10的后面。(因为int会溢出,这里采用long记录数字)
- step 3:然后比较两个数字大小,根据大小关系返回1或者-1,如果全部比较完都无法比较出大小关系,则返回0.
public int compare (String version1, String version2) {// write code hereint len1 = version1.length(), len2 = version2.length();int n1 = 0, n2 = 0;while (n1 < len1 || n2 < len2) {int num1 = 0, num2 = 0; //每个点间的数字while (n1 < len1 && version1.charAt(n1) != '.') {num1 = num1 * 10 + version1.charAt(n1++) - '0';}while (n2 < len2 && version2.charAt(n2) != '.') {num2 = num2 * 10 + version2.charAt(n2++) - '0';}//判断每个点间的数字大小if (num1 > num2) return 1;else if (num1 < num2) return -1;n1++;n2++;//跳过点}return 0;
}
27、二叉树的前序遍历
//递归方式
public int[] preorderTraversal (TreeNode root) {// write code hereList<Integer> list = new ArrayList<>();preorder(root, list);int[] res = new int[list.size()];for (int i = 0; i < list.size(); i++) {res[i] = list.get(i);}return res;
}
public void preorder(TreeNode node, List<Integer> list) {if (node == null) return;list.add(node.val);preorder(node.left, list);preorder(node.right, list);
}
//非递归方式
public int[] preorderTraversal (TreeNode root) {//添加遍历结果的数组List<Integer> list = new ArrayList();Stack<TreeNode> s = new Stack<TreeNode>();//空树返回空数组if(root == null)return new int[0];//根节点先进栈s.push(root);while(!s.isEmpty()){//每次栈顶就是访问的元素TreeNode node = s.pop();list.add(node.val);//如果右边还有右子节点进栈if(node.right != null)s.push(node.right);//如果左边还有左子节点进栈if(node.left != null)s.push(node.left);}//返回的结果int[] res = new int[list.size()];for(int i = 0; i < list.size(); i++)res[i] = list.get(i);return res;
}
28、二叉树的中序遍历
public int[] inorderTraversal (TreeNode root) {// write code here// 递归方式List<Integer> list = new ArrayList<>();inorder(root, list);int[] res = new int[list.size()];for (int i = 0; i < list.size(); i++) {res[i] = list.get(i);}return res;
}
public void inorder(TreeNode root, List<Integer> list) {if (root == null) return;inorder(root.left, list);list.add(root.val);inorder(root.right, list);
}public int[] inorderTraversal (TreeNode root) {//非递归方式//每棵子树,整棵树左边界依次进栈,依次弹出,处理,对右树循环//添加遍历结果的数组List<Integer> list = new ArrayList(); Stack<TreeNode> s = new Stack<TreeNode>();//空树返回空数组if(root == null) return new int[0];//当树节点不为空或栈中有节点时while(root != null || !s.isEmpty()){ //每次找到最左节点while(root != null){ s.push(root);root = root.left;}//访问该节点TreeNode node = s.pop(); list.add(node.val); //进入右节点root = node.right; }//返回的结果int[] res = new int[list.size()]; for(int i = 0; i < list.size(); i++)res[i] = list.get(i);return res;
}
29、二叉树的后序遍历
public int[] postorderTraversal (TreeNode root) {// write code hereList<Integer> list = new ArrayList<>();postorder(root, list);int[] res = new int[list.size()];for (int i = 0; i < list.size(); i++) {res[i] = list.get(i);}return res;
}
public void postorder(TreeNode root, List<Integer> list) {if (root == null) return;postorder(root.left, list);postorder(root.right, list);list.add(root.val);
}//非递归,头入栈,放入另一个栈,先左后右
public int[] postorderTraversal (TreeNode root) {// write code hereList<Integer> list = new ArrayList<>();Stack<TreeNode> stack1 = new Stack<>();Stack<TreeNode> stack2 = new Stack<>();stack1.push(root);if (root == null) return new int[0];while (!stack1.isEmpty()) {TreeNode node = stack1.pop();stack2.push(node);if (node.left != null) {stack1.push(node.left);}if (node.right != null) {stack1.push(node.right);}}while (!stack2.isEmpty()) {list.add(stack2.pop().val);}int[] res = new int[list.size()];for (int i = 0; i < list.size(); i++) {res[i] = list.get(i);}return res;
}
30、求二叉树的层序遍历
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHAsUcY5-1677307640261)(${img}/Untitled 23.png)]
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {// write code hereArrayList<ArrayList<Integer>> array = new ArrayList<>();if (root == null) return array;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {ArrayList<Integer> temp = new ArrayList<Integer>();int n = queue.size();//该层数量while (n-- > 0) {TreeNode node = queue.poll();temp.add(node.val);if(node.left!=null) queue.offer(node.left);if(node.right!=null) queue.offer(node.right);}array.add(temp);}return array;
}
31、按之字形顺序打印二叉树
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {ArrayList<ArrayList<Integer>> array = new ArrayList<>();if (pRoot == null) return array;Queue<TreeNode> queue = new LinkedList<>();boolean flag = true;queue.add(pRoot);while (!queue.isEmpty()) {ArrayList<Integer> temp = new ArrayList<Integer>();int n = queue.size();//该层数量while (n-- > 0) {TreeNode node = queue.poll();temp.add(node.val);if (node.left != null) queue.add(node.left);if (node.right != null) queue.add(node.right);}//奇数行反转,偶数行不反转flag = !flag;if (flag)Collections.reverse(temp);array.add(temp);}return array;
}
32、二叉树的最大深度
public int maxDepth (TreeNode root) {// write code here// 递归终止if (root == null) {return 0;}// dfs,先递归左子结点,再递归右子结点,最后求出每一子树的深度的最大值return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}public int maxDepth (TreeNode root) {// write code hereif (root == null) return 0;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);int res = 0;while (!queue.isEmpty()) {int n = queue.size();//该层数量while (n-- > 0) {TreeNode node = queue.poll();if (node.left != null) queue.offer(node.left);if (node.right != null) queue.offer(node.right);}res++;}return res;
}
33、二叉树中和为某一值的路径(一)
遍历的方法我们可以选取二叉树常用的递归前序遍历,因为每次进入一个子节点,更新sum值以后,相当于对子树查找有没有等于新目标值的路径,因此这就是子问题,递归的三段式为:
- 终止条件: 每当遇到节点为空,意味着过了叶子节点,返回。每当检查到某个节点没有子节点,它就是叶子节点,此时sum减去叶子节点值刚好为0,说明找到了路径。
- 返回值: 将子问题中是否有符合新目标值的路径层层往上返回。
- 本级任务: 每一级需要检查是否到了叶子节点,如果没有则递归地进入子节点,同时更新sum值减掉本层的节点值。
具体做法:
- step 1:每次检查遍历到的节点是否为空节点,空节点就没有路径。
- step 2:再检查遍历到是否为叶子节点,且当前sum值等于节点值,说明可以刚好找到。
- step 3:检查左右子节点是否可以有完成路径的,如果任意一条路径可以都返回true,因此这里选用两个子节点递归的或。
public class Solution {public boolean hasPathSum (TreeNode root, int sum) {// write code hereif (root == null) return false;return dfs(root, sum);}public boolean dfs(TreeNode node, int target) {if (node == null) return false;// 目标路径不存在,开始回溯target -= node.val; // 更新目标值 // 当前节点为叶子节点并且目标路径存在时,返回 trueif (node.left == null && node.right == null && target == 0) return true;return dfs(node.left, target) || dfs(node.right, target);}
}
34、二叉搜索树与双向链表
//递归
public class Solution {private TreeNode head = null;//起始位置private TreeNode pre = null;//不断更新的位置public TreeNode Convert(TreeNode pRootOfTree) {if (pRootOfTree == null) return null;//中序遍历即为有序Convert(pRootOfTree.left);if (head == null) {head = pRootOfTree;//最左端pre = head;} else {pre.right = pRootOfTree;//右指针指向后继pRootOfTree.left = pre;//左指针指向前继pre = pRootOfTree; //更新位置}Convert(pRootOfTree.right);return head;}
}//非递归
public class Solution {public TreeNode Convert(TreeNode pRootOfTree) {if (pRootOfTree == null)return null;//使用非递归方式Stack<TreeNode> s = new Stack<>();TreeNode head = null;TreeNode pre = null;boolean flag = true;while (pRootOfTree != null || !s.isEmpty()) {//直到没有左节点while (pRootOfTree != null) {s.push(pRootOfTree);pRootOfTree = pRootOfTree.left;//更新最左边}TreeNode node = s.pop();//弹出//处理if (flag) {//第一次最左边head = node;pre = head;flag = false;} else {pre.right = node;//右指针指向后继node.left = pre;//左指针指向前继pre = node;//更新}pRootOfTree = node.right;//进入右边}return head;}
}
35、对称的二叉树
遍历方式依据前序递归可以使用递归:
- 终止条件: 当进入子问题的两个节点都为空,说明都到了叶子节点,且是同步的,因此结束本次子问题,返回true;当进入子问题的两个节点只有一个为空,或是元素值不相等,说明这里的对称不匹配,同样结束本次子问题,返回false。
- 返回值: 每一级将子问题是否匹配的结果往上传递。
- 本级任务: 每个子问题,需要按照上述思路,“根左右”走左边的时候“根右左”走右边,“根左右”走右边的时候“根右左”走左边,一起进入子问题,需要两边都是匹配才能对称。
具体做法:
- step 1:两种方向的前序遍历,同步过程中的当前两个节点,同为空,属于对称的范畴。
- step 2:当前两个节点只有一个为空或者节点值不相等,已经不是对称的二叉树了。
- step 3:第一个节点的左子树与第二个节点的右子树同步递归对比,第一个节点的右子树与第二个节点的左子树同步递归比较。
public class Solution {boolean isSymmetrical(TreeNode pRoot) {if(pRoot == null) return true;return recursion(pRoot.left, pRoot.right);}private boolean recursion(TreeNode left, TreeNode right) {if (left == null && right == null) return true;//可以两个都为空if (left == null || right == null || left.val != right.val) return false;//只有一个为空或者节点值不同,必定不对称return recursion(left.left, right.right) && recursion(left.right, right.left);//每层对应的节点进入递归比较}
}
//非递归
public class Solution {boolean isSymmetrical(TreeNode pRoot) {if(pRoot == null) return true;Queue<TreeNode> q1 = new LinkedList<>();//左边子树Queue<TreeNode> q2 = new LinkedList<>();//右边子树q1.offer(pRoot.left);q2.offer(pRoot.right);while(!q1.isEmpty()&&!q2.isEmpty()){TreeNode n1 = q1.poll();//leftNodeTreeNode n2 = q2.poll();//rightNode//判断if(n1 == null && n2 == null) continue;if(n1 == null || n2 == null || n1.val != n2.val) return false;q1.offer(n1.left);q2.offer(n2.right);q1.offer(n1.right);q2.offer(n2.left);}return true;}}
36、合并二叉树
public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {// write code hereif (t1 == null) return t2;if (t2 == null) return t1;TreeNode node = new TreeNode(t1.val + t2.val);node.left = mergeTrees(t1.left, t2.left);node.right = mergeTrees(t1.right, t2.right);return node;
}
37、二叉树的镜像
public TreeNode Mirror (TreeNode pRoot) {// write code here// 先序遍历,从顶向下交换if(pRoot == null) return null;//父问题 交换两个子节点的值。TreeNode temp = pRoot.left;pRoot.left = pRoot.right;pRoot.right = temp;Mirror(pRoot.left);//左子树交换Mirror(pRoot.right);//右子树交换return pRoot;
}
38、判断是不是二叉搜索树
class Solution {long pre = Long.MIN_VALUE; //前一个左子树的值public boolean isValidBST(TreeNode root) {if(root == null) return true;if(!isValidBST(root.left)) return false;if(pre >= root.val) return false;pre = root.val;return isValidBST(root.right);}
}
39、判断是不是完全二叉树
public class Solution {public boolean isCompleteTree (TreeNode root) {// write code here// BFSif(root == null) return true;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);boolean isComplete = true;while(!queue.isEmpty()){TreeNode node = queue.poll();if(node == null){//第一次遇到nullisComplete = false;continue;}//遇到null后不应该再遇到非空节点了if(!isComplete) return false;queue.offer(node.left);queue.offer(node.right);}return true;}
}
40、判断是不是平衡二叉树
public class Solution {public boolean IsBalanced_Solution(TreeNode root) {if (root == null) return true;//父问题:左右两个子树的高度差的绝对值不超过1int left = deep(root.left);int right = deep(root.right);if (Math.abs(left - right) > 1) return false;//子问题:左右两个子树都是一棵平衡二叉树。return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);}private int deep(TreeNode node) {if (node == null) return 0;//子问题:左右子树高度int left = deep(node.left);int right = deep(node.right);//父问题:左右子树的最大高度return Math.max(left,right) + 1;}
}
41、二叉搜索树的最近公共祖先
利用二叉搜索树的性质:对于某一个节点若是p与q都小于等于这个这个节点值,说明p、q都在这个节点的左子树,而最近的公共祖先也一定在这个节点的左子树;若是p与q都大于等于这个节点,说明p、q都在这个节点的右子树,而最近的公共祖先也一定在这个节点的右子树。
具体做法:
- step 1:首先检查空节点,空树没有公共祖先。
- step 2:对于某个节点,比较与p、q的大小,若p、q在该节点两边说明这就是最近公共祖先。
- step 3:如果p、q都在该节点的左边,则递归进入左子树。
- step 4:如果p、q都在该节点的右边,则递归进入右子树。
public int lowestCommonAncestor (TreeNode root, int p, int q) {if (root.val<p && root.val<q) {return lowestCommonAncestor(root.right,p,q);}if (root.val>p && root.val>q) {return lowestCommonAncestor(root.left,p,q);}return root.val;
}
42、在二叉树中找到两个节点的最近公共祖先
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {// write code hereif(root == null) return -1;if(root.val == o1 || root.val == o2) return root.val; //和头有关//和头无关int left = lowestCommonAncestor(root.left, o1, o2); //左子树寻找公共祖先 , 子树信息int right = lowestCommonAncestor(root.right, o1, o2); //右子树寻找公共祖先 , 子树信息if(left != -1 && right != -1) return root.val; //左右子树找到了 整合出信息return left == -1 ? right : left;
}
43、序列化二叉树
import java.util.*;
public class Solution {StringBuilder sb = new StringBuilder();String Serialize(TreeNode root) {SerializeHelp(root, sb);return sb.toString();}TreeNode Deserialize(String str) {String[] values = str.split("_");//队列中存放分隔后的数据,value和#Queue<String> queue = new LinkedList<>();for (int i = 0; i < values.length; i++) {queue.offer(values[i]);}return DeserializeHelp(queue);}void SerializeHelp(TreeNode node, StringBuilder sb) {//先序遍历 null 为#_ ,其他分隔符为_if (node == null) {sb.append("#_");return; //结束}sb.append(node.val + "_");SerializeHelp(node.left, sb);SerializeHelp(node.right, sb);}TreeNode DeserializeHelp(Queue<String> queue) {String value = queue.poll();if (value.equals("#")) return null; //遇到# 表示空节点TreeNode node = new TreeNode(Integer.valueOf(value));node.left = DeserializeHelp(queue);node.right = DeserializeHelp(queue);return node;}
}
44、重建二叉树
public class Solution {HashMap<Integer, Integer> map = new HashMap<>();public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {for(int i = 0; i < pre.length; i++){map.put(vin[i], i);//存放中序遍历}return build(pre, vin, 0, pre.length - 1, 0, pre.length - 1);}private TreeNode build(int [] pre,int [] vin, int pl, int pr, int vl, int vr){if(pl > pr || vl > vr) return null;int r = map.get(pre[pl]) - vl;//获取中序遍历的根节点TreeNode root = new TreeNode(pre[pl]);//左子树root.left = build(pre, vin, pl + 1, pl + r, vl, vl + r - 1);//右子树root.right = build(pre, vin, pl + r + 1, pr, vl + r + 1, vr);return root;}
}
45、输出二叉树的右视图
import java.util.*;public class Solution {public int[] solve (int[] xianxu, int[] zhongxu) {// write code here//1、重建树TreeNode root = rebuildTree(xianxu, zhongxu);//2、右视图List<Integer> list = new ArrayList<>();rightview(root, list);//3、将list变为int[]int[] ans = new int[list.size()];for (int i = 0; i < list.size(); i++) {ans[i] = list.get(i);}return ans;}private TreeNode rebuildTree(int[] xianxu, int[] zhongxu) {int pl = xianxu.length;int ml = zhongxu.length;//分治算法if (pl == 0 || ml == 0) return null;TreeNode node = new TreeNode(xianxu[0]);//根//找到中序根中对应的第一个序号for (int i = 0; i < ml ; i++) {if (xianxu[0] == zhongxu[i]) {node.left = rebuildTree(Arrays.copyOfRange(xianxu, 1, i + 1),Arrays.copyOfRange(zhongxu, 0, i));node.right = rebuildTree(Arrays.copyOfRange(xianxu, i + 1, pl),Arrays.copyOfRange(zhongxu, i + 1, ml));break;}}return node;}private void rightview(TreeNode root, List<Integer> list) {//层序遍历if (root == null) return;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {int size = queue.size();while (size-- != 0) {TreeNode node = queue.poll();if (node.left != null) queue.offer(node.left);if (node.right != null) queue.offer(node.right);if (size == 0) list.add(node.val); //层序的最后一个值}}}}
相关文章:
面试必刷101 Java题解 -- part 1
练习地址 面试必刷101-牛客1、链表反转2、链表内指定区间反转**3. 链表中的节点每k个一组翻转**4、**合并两个排序的链表**5、**合并k个已排序的链表**6、**判断链表中是否有环****7、链表中环的入口结点**8、链表中倒数最后k个结点**9、删除链表的倒数第n个节点****10、两个链…...
Python---关联与继承
专栏:python 个人主页:HaiFan. 专栏简介:Python在学,希望能够得到各位的支持!!! 关联与继承前言has a关联关系is a继承关系子类不添加__init__子类添加__init__前言 has a关联关系 has - a 是在…...
数据库行业的 “叛逆者”:大数据已“死”,MotherDuck 当立
“大数据”已死——现今我们最重要的事情不是担心数据大小,而是专注于我们将如何使用它来做出更好的决策。数据库行业发展至今,在数据层面有很多的加速和变革,尤其是过去几年的云数仓爆炸式增长,带来了行业的很多变化。毫无疑问&a…...
Linux->进程优先级
目录 1. 优先级的概念 2. 优先级的运作方式 3. Linux下查看进程优先级以及调整 3.1 查看进程优先级 3.2 修改进程优先级 1. 优先级的概念 1. cpu资源分配的先后顺序,就是指进程的优先权(priority)。 2. 优先权高的进程有优先执行权利。配…...
loki 日志管理的安装部署使用
loki介绍 Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签。 不对日志进行…...
CTFer成长之路之反序列化漏洞
反序列化漏洞CTF 1.访问url: http://91a5ef16-ff14-4e0d-a687-32bdb4f61ecf.node3.buuoj.cn/ 点击下载源码 本地搭建环境并访问url: http://127.0.0.1/www/public/ 构造payload: ?sindex/index/helloðanwhoamiPOST的参数&#…...
Python学习-----模块5.0(文件管理大师-->os模块)
目录 前言: 1.os.getcwd() 2. os.listdir(path) 3.os.walk(path) 4.os.path.exists(path) 5.os.mkdir(path) 6.os.makedirs(path,exist_okTrue) 7.os.rmdir(path) 8.os.remove(path) 9.os.path.join(p1,p2) 10.os.path.split(path) 11.os.path.isdi…...
第45届世界技能大赛“网络安全”赛项浙江省选拔赛竞赛任务书
第45届世界技能大赛浙江省选拔赛竞赛任务书 一、竞赛时间 8:00-17:00,共计9小时。 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 模块A 任务1 数据库安全加固 8:00-10:00 50 任务2 文件MD5校验 50 任务3 Linux系统服务渗透测试及安全加…...
【uniapp微信小程序】跨平台使用echarts的方案选择踩坑
一、前言 使用Uniapp(vue)开发微信小程序,想用echarts图表实现类似github热力图的效果。 简要列一些可行或不可行的方案。 二、方案对比 1. 【应用】:微信小程序原生开发 有echarts官网提供的跨平台方案:在微信小程…...
WAF渗透攻防实践(16)
预备知识 WAF:WEB攻击一直是黑客攻击的主流手段,WAF作为网站安全基础设施的标配。Web Application Firewall,Web应用防火墙,通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的产品。 Nginx:Nginx 是…...
高并发场景下机器性能优化sop
之前接触过一些高并发场景下的性能优化,最近过年时候又碰巧看了一些相关资料,趁着还没忘干净,手动整理一下,有一些是在别处看到的,有一些是自己的亲身经历,因为偏向于自己整理笔记所以很多地方都只是列了一…...
【女程序员进大厂面试经验】
*那些犹豫想做技术又不敢的女生一定不要胆怯,就认准了这条路坚持走下去。大三的学生已经可以开始投简历、寻找面试机会了。先说一下我的情况吧!我是郑州一双普通本科的女大学生,刚找工作的时候也很迷茫。同班的女生有做产品的、有做前端的、还…...
计算机网络笔记(复试准备)第一章
计算机网络笔记(复试准备) 第一章 网络,互联网与因特网 网络由若干个结点和连接这些结点的链路组成 多个网络通过路由器连接起来这也就形成了一个更大的网络即是我们熟知的互联网也就是“网络的网络” 因特网是世界上最大的网络 问…...
WooCommerce 上传文件 Vanquish v71.6
今天用wp 搭一个b2c外贸跨境电商网站 找 了一个文件上传插件,可以 上传无限数量的文件,没有文件大小限制WooCommerce 上传文件允许您上传无限数量的文件,没有任何文件大小限制。得益于其创新的块上传技术,它可以不受限制地上传任何…...
zabbix4.0 Web页面配置 - 聚合图形的实现
目录 1、主机组Host groups配置 创建主机组 编辑 将一个主机添加至刚才创建的主机里面 2、用户参数UserParameter设置 示例: 添加一个参数:show.host.messages 模拟zabbix模板里面的参数再添加一个userparameter 3、触发器设置 示例: …...
计算机网络 — UDP协议(看这一篇就可以
UDP协议UDP是传输层的重要协议之一,另一重要协议为TCP协议。两者对比:TCP协议复杂,但传输可靠。UDP协议简单,但传输不可靠。UDP协议全称为:User Datagram Protocol(用户数据报协议)。它是一个简…...
Pikachu靶场(暴力破解)
目录标题暴力破解(登录)基于表单的暴力破解验证码绕过(on server)验证码绕过(on client)token防爆破?上学期用这个靶场写过作业,现在抽空给它过一遍,由于需要抓包,从而通过小皮,使用本地(127.0…...
浅谈script,link,import,@import引入
一.页面导入样式,使用link和import有什么区别 链接式和导入式有什么区别(链接式,导入式,内嵌式,行内) 1.从属关系:link是html标签,import是css提供的. 2.加载差异:页面加载时,link会…...
【CSS】CSS 层叠样式表 ① ( 简介 | CSS 引入方式 - 内联样式 | 内联样式语法 | 内联样式缺点 )
文章目录一、CSS 层叠样式表二、CSS 引入方式 - 内联样式1、内联样式语法2、内联样式缺点3、内联样式代码示例① 核心代码示例② 完整代码示例③ 执行结果一、CSS 层叠样式表 CSS 全称 Cascading Style Sheets , 层叠样式表 ; 作用如下 : 设置 HTML 页面 文本内容 的 字体 , 颜…...
12.STM32系统定时器-SysTick
目录 1.系统定时器-SysTick 2.SysTick定时时间的计算 3.SysTick结构体 4.SysTick固件库函数 5.SysTick中断优先级 1.系统定时器-SysTick SysTick:24位系统定时器,只能递减,存在于内核嵌套在NVIC中。所有的Cortex-M中都有这个系统定时器。 重装载值…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...
