解题思路:(1) 最简单的方法是从后往前遍历(需要两层循环),但是这样时间复杂度太高了,力扣上不能全过。(2) 由题可知,数值范围为0~n-1,所以可以创建一个辅助数组,让原始序列通过取余操作映射到辅助数组上,当辅助数据记录两次同一个元素时,表明该数字是重复的,直接返回就可以了。

int findRepeatNumber(vector<int>& nums) {int temp, size = nums.size();vector<int> a(size, 0);for(int i = 0; i < size; i++){temp = nums[i]%size;a[temp]++;if(a[temp] >= 2)break;}return temp;
}int findRepeatNumber(vector<int>& nums) {unordered_map<int, bool> map;for(int num : nums) {if(map[num]) return num;map[num] = true;}return -1;
}

解题思路:题中说明每一行和每一列都是按照递增顺序排序的。所以在找 target 的时候,可以从数组的右上角开始。若 matrix[rows][columns] > target,因为列是从上往下递增的,所以这一列就不用再考虑了,令 columns--。若 matrix[rows][columns] < target,因为行是从左往右递增的,所以这一行就不用再考虑了,令 rows++。如果能找到 target 则返回 true,反之返回 false。

class Solution {
public:bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {if(matrix.size() == 0) return false;int columns = matrix[0].size() - 1, rows = 0;//先计算行和列,循环条件是列大于0,行不超过二维数组的行数while(columns >= 0 && rows < matrix.size()){if(matrix[rows][columns] > target)  columns--;else if(matrix[rows][columns] < target)  rows++;else return true;}return false;}
};

解题思路:先计算出空格的数量,再做一个扩容的操作,然后就是从后往前复制元素的工作。

string replaceSpace(string s) {if(s.empty()) return s;int spaceCount = 0, i = s.size() - 1;for(char c : s){                        //计算空格的数量if(c == ' ') spaceCount ++;}s.resize(s.size() + spaceCount * 2);    //扩容int j = s.size() - 1;                   while(i != j)                           //i是扩容前的最后一个元素下标,j是扩容后的最后一个元素的下标{                                       //从后往前替换空格if(s[i] != ' '){s[j--] = s[i--];}else{s[j--] = '0';s[j--] = '2';s[j--] = '%';i--;}}return s;
}

解题思路:(1) 用栈先进后出的性质。(2) 使用数组复制链表的值,然后做一个反转操作。 (3) 递归的过程中,将值 push 到 vector 中。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/用栈
vector<int> reversePrint(ListNode* head) {vector<int> res;stack<int> s;ListNode *p = head;while(p){s.push(p->val);p = p->next;}while(!s.empty()){res.push_back(s.top());s.pop();}return res;
}用数组
vector<int> reversePrint(ListNode* head) {vector<int> res;ListNode *p = head;while(p){res.push_back(p->val);p = p->next;}reverse(res.begin(),res.end());return res;
}递归过程中添加到 vector
vector<int> asd;
void reversePrint(ListNode* head)
{if(head != NULL){if(head->next != NULL)reversePrint(head->next);}asd.push_back(head->value);
}

解题思路:因为栈是先进后出的,所以当一个序列进入一个栈后出栈得到的序列再进入另一个栈后出栈,得到的序列和原序列一样。两个栈实现队列,其中 stack1 用于添加数据,即入队操作。stack2 用于删除数据,即出队操作。入队时,将元素 push 到 stack1 中。出队时,pop 出 stack2 中的元素即可。如若 stack2 此时为空,需要从 stack1 中的所有元素迁移到 stack2 后再完成 pop 操作。

class CQueue {stack<int> stack1, stack2; //stack1用来添加数据   stack2用来删除数据
public:CQueue() {while (!stack1.empty()) {stack1.pop();}while (!stack2.empty()) {stack2.pop();}}void appendTail(int value) {stack1.push(value);}int deleteHead() {//如果第二个栈为空,此时还要出队,就要把第一个栈的元素push到第二个栈中if (stack2.empty()) {while (!stack1.empty()) {stack2.push(stack1.top());stack1.pop();}} if (stack2.empty()) {return -1;} else {int deleteItem = stack2.top();stack2.pop();return deleteItem;}}
};

解题思路:斐波那契数列的规律:f(n+1) = f(n) + f(n−1)。

class Solution {
public:int fib(int n) {int result[2] = {0,1};if(n < 2)return result[n];long long fibone = 1;long long fibtwo = 0;long long fib = 0;//性质 f(n+1)=f(n)+f(n−1) for(unsigned int i = 2; i <= n; ++i){fib = (fibone + fibtwo)%(1000000007);fibtwo = fibone;fibone = fib;}return fib;}
};

解题思路:青蛙跳台阶的规律:f(n) = f(n-1) + f(n-2) 。本题可转化为 求斐波那契数列第 n 项的值,与斐波那契数列等价,唯一的不同在于起始数字不同。

斐波那契数列问题: f(0) = 0, f(1) = 1, f(2) = 1。

青蛙跳台阶问题: f(0) = 1, f(1) = 1, f(2) = 2。

class Solution {
public:int numWays(int n) {if(n == 0 || n == 1) return 1;int N = 0, One = 1, Two = 1;while(n >= 2){// f(n) = f(n-1) + f(n-2);// 采取从下往上的方法,把计算过的中间项保存起来,避免重复计算导致递归调用栈溢出N = (One + Two) % 1000000007;Two = One;One = N;n--;}return N;}
};

解题思路:该题最简单的方式是遍历数组找最小值,但是如果真的出该题,一般都会对时间复杂度做出要求。由于这是一个递增的数组旋转后的结果,所以当下标为 mid 的元素小于下标为 high 的元素时,最小的元素一定在 mid 的左侧(包括 mid,所以令 high = mid)。而当下标为 mid 的元素大于下标为 high 的元素时,最小的元素一定在 mid 的右侧(此时不包括 mid,所以令 low = mid + 1)。

class Solution {
public:int minArray(vector<int>& numbers) {int low = 0;int high = numbers.size() - 1;while (low < high) {int mid = low + (high - low) / 2;if (numbers[mid] < numbers[high]) {high = mid;}else if (numbers[mid] > numbers[high]) {low = mid + 1;}else {high -= 1;}}return numbers[low];}
};

有一些二分法的题解写的是 low + (high - low) / 2 而不是 (high + low) / 2。因为 low+high 在 low 和  high 特别大的时候可能会造成溢出,使用减法能避免溢出的发生。

解题思路:使用 DFS 解题,从左到右,从上到下遍历。遇到第一个与字符串第一个值相等的位置时,以该位置为起点,进行深度优先搜索。当行列值不满足矩阵的范围时,直接返回 false,反之,继续进行搜索。注意,当搜索到一个位置的时候,需要将这个元素替换成 '\0',表明当前元素暂时不参与比较。

class Solution {
public:bool exist(vector<vector<char>>& board, string word) {if(word.empty()) return false;for(int i = 0; i < board.size(); ++i){for(int j = 0; j < board[0].size(); ++j){   if(dfs(board, word, i, j, 0)) return true;}}return false;}bool dfs(vector<vector<char>>& board, string& word, int i, int j, int index){if(i<0 || i>=board.size() || j<0 || j>=board[0].size() || board[i][j]!=word[index]) return false;if(index == word.length() - 1) return true;char temp = board[i][j];board[i][j] = '\0'; // 将当前元素标记为'\0',表明当前元素不可再参与比较if(dfs(board,word,i-1,j,index+1) || dfs(board,word,i+1,j,index+1) || dfs(board,word,i,j-1,index+1) || dfs(board,word,i,j+1,index+1)){// 当前元素的上下左右,如果有匹配到的,返回truereturn true;}board[i][j] = temp; // 将当前元素恢复回其本身值return false;}
};

解题思路:该题整体思路与矩阵中的路径一样。不同的是,该题需要一个 bool 型数组记录走过的方块,防止重复计数。

class Solution {
public:int getsum(int n){int sum = 0;while( n > 0 ){sum += n%10;n /= 10;}return sum;}bool check(int t, int rows, int cols, int row, int col, bool* visited){if(row >= 0 && row < rows && col >= 0 && col < cols&& getsum(row) + getsum(col) <= t&& !visited[row*cols + col])return true;return false;}int movingcountCore(int t, int rows, int cols, int row, int col, bool* visited){int count = 0;if(check(t, rows, cols, row, col, visited)){visited[row*cols + col] = true;count = 1 + movingcountCore(t, rows, cols, row-1, col, visited) +movingcountCore(t, rows, cols, row+1, col, visited) +movingcountCore(t, rows, cols, row, col-1, visited) +movingcountCore(t, rows, cols, row, col+1, visited);}return count;}int movingCount(int m, int n, int k) {   //m是行,n是列,k是阈值。if(k < 0 || m <= 0 || n <= 0)return 0;// movingCount 完成基本的判断,调用 movingcountCore 完成工作// visited 用来记录访问过的单元bool* visited = new bool[m*n];for(int i = 0; i < m*n; ++i)visited[i] = false;int count = movingcountCore(k, m, n, 0, 0, visited);delete []visited;return count;}
};

解题思路:(1) 动态规划剪绳子的性质:f(n) = max( f(i) * f(n-i) ),特殊处理:使用一个res数组是做记忆化处理用的。如果某个长度的绳子,剪了一下之后,其中一段的长度在 [0,3] 的区间内,就不要再剪这一段了。因为剪了之后,乘积会变小,而 res[i] 是长度为 i 的绳子剪成若干段后能获得的最大乘积,所以 res[0] 到 res[3] 要单独处理。当长度大于等于 4 时,利用 f(n) = max( f(i) * f(n-i) ) 记录绳子的最大乘积。

(2) 该题最简单的解法是使用贪心算法。当 n 大于等于 5 时,可以推导出,n 的组合中剪出 3 的绳子的段数越多,相应的乘积越大。所以为了得到最优解,应该尽可能地多剪长度为 3 的绳子。当问题规模 n 变大时,需要根据题目需求取模。

class Solution {
public:int cuttingRope(int n) {//动态规划剪绳子: f(n) = max( f(i)*f(n-i) );if(n <= 3) return n - 1; // 当绳子的总长度<=3时,做特殊情况处理vector<int> res(n + 1, 0); // res[i]表示长度为i的绳子剪成若干段之后,乘积的最大值//特殊处理:如果某个长度的绳子,剪了一下之后,其中一段的长度在[0,3]的区间内,就不要再剪这一段了//因为剪了之后,乘积会变小,而res[i]是长度为i的绳子剪成若干段后能获得的最大乘积//所以[res[0],res[3]]要单独处理(如下)res[0] = 0;res[1] = 1;res[2] = 2;res[3] = 3;           //比如3再剪的话最大值就是2,比原来还小,所以不剪了int maxProduct = 0;for(int i = 4; i <= n; ++i){maxProduct = 0;for(int j = 1; j <= i/2; ++j){//循环体中写i/2是为了减少计算次数(因为比如1x3和3x1值是一样的,计算一次即可)int temp = res[j] * res[i-j];maxProduct = max(maxProduct, temp);res[i] = maxProduct; // res数组是做记忆化处理用的}}return res[n];}
};
class Solution {
public:int cuttingRope(int n) {if(n <= 3)  return n-1;int res = 1;while(n > 4){n    = n - 3;           //尽可能地多剪长度为3的绳子res  = res * 3;         }return res * n;}
};

解题思路:通过左移和与操作计算一个数字的二进制形式中 1 的个数。

class Solution {
public:int hammingWeight(uint32_t n) {int count = 0;unsigned int flag = 1;while(flag){if(n & flag)count++;flag = flag << 1;}return count;}
};

解题思路:需要用到快速幂的思想。其核心相当于将问题做了一个转换,例如:2^(4) 转换成 ( 2^(2) )^(2),即 4^(2)。所以下面的代码中 x *= x; 和 exp >>= 1; 是成对出现的。

class Solution {
public:double myPow(double x, int n) {if(n == 0 || x == 1.0) return 1;if(x == 0.0 && n < 0) return x; // 当x是0而n是负数的时候,特殊情况double res = 1.0;long exp = n; // 必须是long,否则如果n=INT_MIN,-n会越界if(exp < 0){x = 1 / x;exp = -exp;}while(exp)   // 核心{// 快速幂方法(位运算)// 假如n=9,9写成二进制就是1001// 每当exp & 1 = 1的时候,就执行乘方运算if(exp & 1) res *= x;x *= x;exp >>= 1;}return res;}
};

解题思路:直接 for 循环打印也是可以的,但是这种题不应该只是这种难度。面试的时候可能会把它作为一道大数问题来考。作为大数问题,首先要考虑到当n很大的时候(比如100),打印出来的数很有可能是超过了 INT_MAX 的范围的,所以需要用字符串来表示每个数。在这一题中,由于返回的是一个 int 型的数组,所以是不可能超过 INT_MAX 的,但是一般大数问题都不会要求返回 int 数组来保存每一位数,而是循环输出每一位数。

class Solution {
public:vector<int> output;vector<int> printNumbers(int n) {// 假设 n = 3if(n <= 0) return vector<int>(0);string s(n, '0'); // s最大会等于999,即s的长度为nwhile(!overflow(s)) inputNumbers(s);return output;}bool overflow(string& s){// 本函数用于模拟数字的累加过程,并判断是否越界(即 999 + 1 = 1000,就是越界情况)bool isOverFlow = false;int carry = 0; // carry表示进位for(int i = s.length()-1; i>=0; --i){int current = s[i] - '0' + carry; // current表示当前这次的操作if(i == s.length() - 1) current++; // 如果i此时在个位,current执行 +1 操作if(current >= 10){// 假如i已经在最大的那一位了,而current++之后>=10,说明循环到头了,即999 + 1 = 1000if(i == 0) isOverFlow = true;else{// 只是普通进位,比如current从10变成11carry = 1;s[i] = current - 10 + '0'; }}else{// 如果没有进位,更新s[i]的值,然后直接跳出循环,这样就可以回去执行inputNumbers函数了,即往output里添加元素s[i] = current + '0';break;}}return isOverFlow;}void inputNumbers(string s){// 本函数用于循环往output中添加符合传统阅读习惯的元素。比如001,我们会添加1而不是001。bool isUnwantedZero = true; // 判断是否是不需要添加的0,比如001前面的两个0string temp = "";for(int i = 0; i < s.length(); ++i){if(isUnwantedZero && s[i] != '0') isUnwantedZero = false;if(!isUnwantedZero) temp += s[i];}output.push_back(stoi(temp));}
};

解题思路:该题提示不需要 free 或 delete 相应结点。若删除的是头结点,则返回头结点后面的结点即可。若删除的不是头结点,遍历过程中找到删除结点的前一个结点后,让其 next 指针指向被删除结点后即可。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* deleteNode(ListNode* head, int val) {if(head == NULL)    return NULL;if(head->val == val) return head->next;ListNode *p = head;while(p->next){if(p->next->val == val){p->next = p->next->next;break;}p = p->next;}return head;}
};

解题思路:主要是用四个变量区分状态:hasNum,hasOp,hasE,hasDot,分别代表拥有数字、正负号、e 和小数点。从前往后逐个字符进行判断,比较好理解的是当遇到 "." 时,如果 hasDot 为真的时候,返回 false,因为一个数字里不能有两个 "."。如果遇到了正负号,而此时 hasOp,hasNum,hasDot 其中有一项为真,则说明该正负号不是开头的符号,所以返回 false(如果有 e 的情况,相应的判断语句会重置其他三个值)。

class Solution {
public:bool isNumber(string s) {int n = s.size();int index = -1;bool hasDot = false,hasE = false,hasOp = false,hasNum = false;while(index<n && s[++index]==' ');while(index<n){if('0'<=s[index] && s[index]<='9'){hasNum = true;}else if(s[index]=='e' || s[index]=='E'){if(hasE || !hasNum) return false;hasE = true;hasOp = false;hasDot = false;hasNum = false;}else if(s[index]=='+' || s[index]=='-'){if(hasOp || hasNum || hasDot) return false;hasOp = true;}else if(s[index]=='.'){if(hasDot || hasE) return false;hasDot = true;}else if(s[index]==' '){break;}else{return false;}++index;}while(index<n && s[++index]==' ');return hasNum && index==n;}
};

解题思路:从前往后找偶数,从后往前找奇数。若下标满足条件,则交换两者的值。

class Solution {
public:vector<int> exchange(vector<int>& nums) {int size = nums.size();if(size == 0)return nums;int low = 0, high = size-1;while(low < high){if(nums[low] % 2 == 1 && low < size)  {low++; continue;}if(nums[high] % 2 == 0 && high > 0)  {high--;  continue;}if(low < high)swap(nums[low++], nums[high--]);}return nums;}
};

解题思路:计算出链表长度,然后从前往后走 len-k 步即可。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* getKthFromEnd(ListNode* head, int k) {if(head == NULL)return NULL;ListNode* p = head;int count = 0;while(p != NULL){count++;p = p->next;}int nodelen = count - k;p = head;while(nodelen--){p = p->next;}return p;}
};

解题思路:使用 3 个指针变量,pre 指向的原序列中当前结点之前的结点,pcur 开始指向头结点,Rp 用于记录反转后的序列的头结点。在反转过程中,先使用 pnext 指向 pcur 的下一个结点,作为一个记录。然后 pcur->next 指向 pre,此时已经让当前结点的 next 指向原序列的 pre 了。接下来让 pre 指向 pcur 后再让 pcur 指向 pnext 即可完成相应的工作。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* pre = NULL, *pcur = head, *Rp = NULL;while(pcur != NULL){ListNode* pnext = pcur->next;if(pnext == NULL)Rp = pcur;pcur->next = pre;pre = pcur;pcur = pnext;}return Rp;}
};

解题思路:递归法和迭代法的思路都比较简单,这里不再赘述。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
迭代法
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(!l1) return l2;if(!l2) return l1;ListNode *dummy = new ListNode(INT_MAX);ListNode *res = dummy;while(l1 && l2){if(l1 -> val < l2 -> val){res -> next = l1;l1 = l1 -> next;}else{res -> next = l2;l2 = l2 -> next;}res = res -> next;}res -> next = l1 ? l1 : l2; // 当有一条链表遍历到头,while循环退出之后,pos->next应指向尚未遍历完的那条链表return dummy -> next;}
};递归法
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(!l1) return l2;if(!l2) return l1;if(l1 -> val < l2 -> val){l1 -> next = mergeTwoLists(l1 -> next, l2);return l1;}else{l2 -> next = mergeTwoLists(l1, l2 -> next);return l2;}}
};

解题思路:进行深度遍历,只有当两者的值相等的时候才判断 A 是否包含 B。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:bool isSubStructure(TreeNode* A, TreeNode* B) {bool result = false;if (A != nullptr && B != nullptr) {if (A->val == B->val) {    //值相等才判断A是否包含Bresult = isTreeAHaveTreeB(A, B);}if (!result) {result = isSubStructure(A->left, B);}if (!result) {result = isSubStructure(A->right, B);}}return result;}bool isTreeAHaveTreeB(TreeNode* A, TreeNode* B) {if (B == nullptr) {return true;     //B已经对比完了,所以返回true}if (A == nullptr) {  //此时B有值,而A却为空,返回falsereturn false;}if (A->val != B->val) {return false;}return isTreeAHaveTreeB(A->left, B->left) && isTreeAHaveTreeB(A->right, B->right);}
};

解题思路:从根开始,交换左右指针。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:TreeNode* mirrorTree(TreeNode* root) {if (root == NULL) {return NULL;}swap(root->left, root->right);mirrorTree(root->left);mirrorTree(root->right);return root;}
};

剑指 offer 编程题 C++ 版总结(上)相关推荐

  1. 剑指 offer 编程题 C++ 版总结(下)

    解题思路:让两个指针分别指向两个链表,当遍历到最末尾的结点后,指针指向另一个链表的头结点.例如:A 和 B 开始的时候分别指向 4 和 5.两个指针分别遍历链表,当 A 遍历到末尾结点的 5 时,下一 ...

  2. 剑指 offer 编程题 C++ 版总结(中)

    解题思路:从根结点开始向下进行对比,(1) 若两边的结点为空,返回 true.(2) 一个结点为空,而另一个结点不为空,此时二叉树不是对称的,返回 false.(3) 两边结点都不为空,但是结点的值不 ...

  3. 剑指offer编程题(JAVA实现)——第35题:数组中的逆序对

    github https://github.com/JasonZhangCauc/JZOffer 剑指offer编程题(JAVA实现)--第35题:数组中的逆序对 题目描述 在数组中的两个数字,如果前 ...

  4. 剑指offer编程题(JAVA实现)——第38题:二叉树的深度

    github https://github.com/JasonZhangCauc/JZOffer 剑指offer编程题(JAVA实现)--第38题:二叉树的深度 题目描述 输入一棵二叉树,求该树的深度 ...

  5. 三天刷完《剑指OFFER编程题》--Java版本实现(第三天)

    正在更新中......... 剑指offer --Python版本的实现: 剑指offer(1/3)第一大部分 剑指offer(2/3)第二大部分 剑指offer(3/3)第三大部分 -------- ...

  6. 剑指Offer——编程题的Java实现(更新完毕……)

    目录 二维数组中的查找 替换空格 从尾到头打印链表 重建二叉树 用两个栈实现队列 用两个队列实现一个栈 旋转数组的最小数字 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 二进制中1的个数 数值的整数次方 ...

  7. 编程 跳台阶_Java版剑指offer编程题第8题--跳台阶

    跟learnjiawa一起每天一道算法编程题,既可以增强对常用API的熟悉能力,也能增强自己的编程能力和解决问题的能力.算法和数据结构,是基础中的基础,更是笔试的重中之重. 不积硅步,无以至千里: 不 ...

  8. 一只青蛙跳向三个台阶_Java版剑指offer编程题第9题--变态跳台阶

    跟learnjiawa一起每天一道算法编程题,既可以增强对常用API的熟悉能力,也能增强自己的编程能力和解决问题的能力.算法和数据结构,是基础中的基础,更是笔试的重中之重. 不积硅步,无以至千里: 不 ...

  9. 剑指Offer——编程题的Java实现

    声明:我写这个的意图是我在看书的过程中,就我掌握的内容做一个笔记,没有抄袭的意图.再次说明一下,我找工作的过程中并不顺利,没有像那些牛人们拿到一大把的Offer,我只是希望通过我自己的努力,不断提高自 ...

最新文章

  1. java不能对什么类型进行转换_关于java:“不兼容类型:void无法转换为…”是什么意思?...
  2. delphi的dbgrid控件点击title排序
  3. 不同的jar里边相同的包名类名怎么区别导入
  4. 洛谷——P1194 买礼物
  5. mongoose如何发送html页面,Mongoose/Express/Nodejs尝试从服务器到html传递变量
  6. 万物皆可Graph | 当推荐系统遇上图神经网络(二)
  7. MATLAB图形插入标题
  8. ProgressBar进度条使用注解
  9. 给C/C++/Java等程序生成API文档
  10. 网易云服务器怎么上传文件,怎么把本地歌曲上传到网易云上
  11. 新浪微博客户端开发之发布微博
  12. 国家职业资格:计算机网络管理员
  13. background 与 background-image
  14. 怎么用C++实现点对点通信
  15. 关于标准电阻阻值的说明(E6、E12、E24、E48、E96、E192)
  16. ng-zorro中树(nz-tree)的拖拽
  17. 【315期】面试官问:在大数据量情况下,如何优化 ElasticSearch 查询?
  18. 精华**2006设计师必备网址全集**精华
  19. 基于underlay和overlay转换的四层负载均衡
  20. 祝贺三八节日 “IT女杰风云榜”专题

热门文章

  1. 1.6 网络编程之 UDP通信
  2. 网狐棋牌游戏平台服务器架构设计分析
  3. 抖音直播间弹幕protocbuf分析
  4. GitHub:再见,master!
  5. StackOverflow 上面最流行的 7 个 Java 问题!| 值得一看
  6. 重新复习一下JDK14的9大重磅特性
  7. Kafka冷门知识——主题删除背后的秘密
  8. 2022校招百度提前批校园招聘
  9. AI加持的竖屏沉浸播放新体验
  10. LiveVideoStack线上交流分享 (九) —— B站的QUIC实践简介