本文将持续更新~~
hello hello~ ,这里是绝命Coding------老白~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹
💥个人主页 :绝命Coding-CSDN博客
💥 所属专栏 :后端技术分享
这里将会不定期更新有关后端、前端的内容,希望大家多多点赞关注收藏💖
双指针算法简介
双指针算法是一种非常常见且实用的算法技巧,它使用两个指针同时在数据结构上移动,从而达到特定的目的。这种算法通常用于解决数组或链表等线性数据结构中的问题,比如寻找某个元素、删除某个元素、反转数组等。
双指针算法有两种常见的使用场景:
- 对撞指针(Two Pointers): 两个指针从不同的方向"对撞"而前进,直到满足某个条件为止。这种方法常用于解决数组或链表的查找、删除等问题。
- 快慢指针(Slow and Fast Pointers): 两个指针以不同的速度移动,比如一个指针每次移动一步,另一个指针每次移动两步。这种方法常用于解决链表中的环检测、链表中点查找等问题。
双指针算法的优点在于它可以在不使用额外空间的情况下解决一些问题,时间复杂度通常是线性的,效率较高。下面我们来总结一下双指针算法的主要特点。
双指针算法总结
- 线性时间复杂度: 由于双指针算法通常只需要遍历一次数据结构,因此时间复杂度通常是O(n)。
- 常数空间复杂度: 双指针算法不需要使用额外的数据结构来存储中间结果,因此空间复杂度通常是O(1)。
- 适用于线性数据结构: 双指针算法主要应用于数组、链表等线性数据结构,可以方便地控制指针的移动。
- 灵活多变: 双指针算法可以根据具体问题的需求,采用不同的指针移动策略,如对撞指针、快慢指针等。
- 易于实现: 双指针算法的思路相对简单,代码实现也较为直观,容易掌握。
力扣算法题
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入: ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入: ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
C------野路子(和+差=第一个,和-差=第二个)
//执行用时: **64 ms**
//内存消耗: **12.2 MB**
void reverseString(char* s, int sSize){
for(int i = 0; i < sSize/2 ; i++){ //注意这里的条件,没有等于号
float add = (float)(s[i] + s[sSize-i-1])/2.0;
float sub = (float)(s[i] - s[sSize-i-1])/2.0;
s[i] = add - sub;
s[sSize-i-1] = add + sub;
}
return;
}
C------双指针(一个i,一个j)
//执行用时: **64 ms**
//内存消耗: **12.1 MB**
void reverseString(char* s, int sSize){
int i=0,j=sSize-1;
for(;i<j;i++,j--){
char a = s[i];
s[i] = s[j];
s[j] = a;
}
return;
}
C++------双指针
//执行用时: **40 ms**
//内存消耗: **22.6 MB**
class Solution {
public:
void reverseString(vector<char>& s) {
int i=0,j=s.size()-1;
for(;i<j;i++,j--){
swap(s[i],s[j]); //优势:可以直接使用函数
}
}
};
【总结:直接双指针首尾交换】
面试题 02.02. 返回倒数第 k 个节点
剑指 Offer 22. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
示例:
给定一个链表: 1->2->3->4->5 , 和 k = 2.
返回链表 4**->5** .
C语言------先计算出倒数第k个是正序的第n个再重新循环输出第n个
//执行用时: **4 ms**
//内存消耗: **5.8 MB**
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
int size=0;
struct ListNode* current;
for(current=head;current!=NULL;current=current->next) size++;
current=head;
for(int i=0;i<size-k;i++) current=current->next;
return current;
}
C++------双指针之快慢指针(倒数第k个:一个指针先走k步,然后和另一指针同时走,直到第一个指针停止为止)(可画图理解)
//执行用时: **0 ms**
//内存消耗: **10.3 MB**
/**
* 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) {
ListNode *first = head;
ListNode *second = head;
//第一个指针先走k步
while( k-- > 0 ){
first = first->next;
}
//然后两个指针同时前进
while( first != NULL ){
first = first->next;
second = second->next;
}
return second;
}
};
总结:倒数第k个用快慢指针:一个指针先走k步,然后和另一个指针一起走,直到结尾
还有方法:递归求解
【总结:第一种方法栈,第二种方法快慢指针】
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出:[1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
C++------类似于冒泡排序
思路:这道题数据量较小,可以使用冒泡排序的思想,将所有 0 依次交换到数组末尾。分析可知,冒泡排序不会改变本题中非零元素的相对顺序,所以符合题目中保持非零元素相对顺序的要求。
//执行用时: **8 ms**
//内存消耗: **8.6 MB**
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int i=0,j=0;
for(;i<nums.size();i++){
// while( nums[j] == 0 ) j++;
if( nums[i] != 0 ){
int tmp = nums[i];
nums[i] = nums[j];
nums[j++] = tmp;
}
}
}
};
面试题 10.01. 合并排序的数组
88. 合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中*,*使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
示例 1:
输入: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入: nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
提示:
- nums1.length == m + n
- nums2.length == n
- 0 <= m, n <= 200
- 1 <= m + n <= 200
- -109 <= nums1[i], nums2[i] <= 109
C语言------类似于归并排序
//执行用时: **4 ms**
//内存消耗: **6.2 MB**
void merge(int* A, int ASize, int m, int* B, int BSize, int n){
int i,j,k;
i=j=k=0;
int temp[ASize];
while( i < m && j < n ){
if( A[i] < B[j] ) temp[k++] = A[i++];
else temp[k++] = B[j++];
}
while( i < m ) temp[k++] = A[i++];
while( j < n ) temp[k++] = B[j++];
for(k=0,i=0;i<ASize;k++,i++) A[i] = temp[k];
}
C++
1.动态创建数组vector<int> tmp(m+n);
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
vector<int> tmp(m+n);
int i = 0,j = 0,k = 0;
while( i < m && j < n ){
if( nums1[i] <= nums2[j] ) tmp[k++] = nums1[i++];
else tmp[k++] = nums2[j++];
}
while( i < m ) tmp[k++] = nums1[i++];
while( j < n ) tmp[k++] = nums2[j++];
for(i=0;i<n+m;i++) nums1[i] = tmp[i];
}
};
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入: ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入: ["H","a","n","n","a","h"]
输出: ["h","a","n","n","a","H"]
C语言
//执行用时: **64 ms**
//内存消耗: **12.1 MB**
void reverseString(char* s, int sSize){
int i=0,j=sSize-1;
for(;i<j;i++,j--){
char a = s[i];
s[i] = s[j];
s[j] = a;
}
return;
}
C++------
//执行用时: **40 ms**
//内存消耗: **22.6 MB**
class Solution {
public:
void reverseString(vector<char>& s) {
int i=0,j=s.size()-1;
for(;i<j;i++,j--){
swap(s[i],s[j]);
}
}
};
125. 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
**说明:**本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
示例 2:
输入: "race a car"
输出: false
1.C++------将大写字母全部转为小写,然后双指针比较
class Solution {
public:
bool isNumAndlet(int str){
//ASCLL 48------------57 65------------90 97------------122
//其实直接'A'这样就行
if( ( str > 47 && str < 58 ) || ( str > 64 && str < 91 ) || ( str > 96 && str < 123 ) )
return true;
else
return false;
}
bool isPalindrome(string s) {
if (s.length() == 0) return true;
int i=0,j=s.length()-1;
//将大写字母全部转为小写
for(int a=0;a<s.length();a++){
if( s[a] > 64 && s[a] < 91 ){
s[a] += 32;
}
}
while(i<j){
//注意这里下面也得有i<j
while( i<j && isNumAndlet(s[i]) == false ) i++;
while( i<j && isNumAndlet(s[j]) == false ) j--;
if( s[i] != s[j] )
return false;
else{
i++;
j--;
}
}
return true;
}
};
2.C++------类似于快速排序
//执行用时: **8 ms**
//内存消耗: **7.7 MB**
class Solution {
public:
bool isVowel(int a){
//aeiou
if(a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u'|| a == 'A'|| a == 'E'|| a== 'I'|| a == 'O'|| a == 'U')
return true;
else
return false;
}
string reverseVowels(string s) {
int i=0,j=s.length()-1;
while(i<=j){
while(i<j && isVowel(s[i]) == false){
i++;
}
while(i<j && isVowel(s[j]) == false){
j--;
}
swap(s[i],s[j]);
i++;
j--;
}
return s;
}
};
3.acwing
(线性扫描) O(n)
用两个指针分别从前后开始,往中间扫描。
每次迭代两个指针分别向中间靠近一步,靠近的过程中忽略除了字母和数字的其他字符。
然后判断两个指针所指的字符是否相等,如果不相等,说明不是回文串。
当两个指针相遇时,说明原字符串是回文串。
时间复杂度分析:每个字符仅会被扫描一次,所以时间复杂度是 O(n)。
class Solution {
public:
bool check(char c)
{
return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
bool isPalindrome(string s) {
int i = 0, j = (int)s.size() - 1;
while (i < j)
{
while (i < j && !check(s[i])) i ++ ;
while (i < j && !check(s[j])) j -- ;
if (s[i] != s[j] && s[i] != (s[j]^32)) return false;
i ++, j --;
}
return true;
}
};
80. 删除有序数组中的重复项 II
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以"引用"方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
示例 1:
输入: nums = [1,1,1,2,2,3]
输出: 5, nums = [1,1,2,2,3]
解释: 函数应返回新长度 length = 5 , 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
示例 2:
输入: nums = [0,0,1,1,1,1,2,3,3]
输出: 7, nums = [0,0,1,1,2,3,3]
解释: 函数应返回新长度 length = 7 , 并且原数组的前五个元素被修改为 0 , 0 , 1 , 1 , 2 , 3 , 3 。 不需要考虑数组中超出新长度后面的元素。
提示:
- 1 <= nums.length <= 3 * 104
- -104 <= nums[i] <= 104
- nums 已按升序排列
(线性扫描) O(n)
由于数组有序,所以相同元素一定是相邻的。
我们定义一个指针 k
,表示新数组的末尾,然后从前往后扫描原数组,如果当前数不等于 nums[k] 且不等于 nums[k−1]
,则将当前数插入新数组的末尾。
时间复杂度分析:总共对原数组仅扫描了一遍,所以总时间复杂度是 O(n)
。
C++ 代码
//执行用时: **4 ms**
//内存消耗: **10.4 MB**
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if( nums.size() < 3 ) return nums.size();
int k = 1;
for(int i = 2; i < nums.size() ; i++ ){
if( nums[i] != nums[k-1] ){
nums[++k] = nums[i];
}
}
k++;
return k;
}
};
977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入: nums = [-4,-1,0,3,10]
输出: [0,1,9,16,100]
解释: 平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入: nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
提示:
- 1 <= nums.length <= 104
- -104 <= nums[i] <= 104
- nums 已按 非递减顺序 排序
进阶:
-
请你设计时间复杂度为 O(n) 的算法解决本问题
//执行用时: 52 ms
//内存消耗: 25.3 MBclass Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0 ; i < nums.size() ; i++ ){
nums[i] = nums[i]*nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
28. 实现 strStr()
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入: haystack = "hello", needle = "ll"
**输出:**2
示例 2:
输入: haystack = "aaaaa", needle = "bba"
输出:-1
示例 3:
输入: haystack = "", needle = ""
**输出:**0
提示:
-
0 <= haystack.length, needle.length <= 5 * 104
-
haystack 和 needle 仅由小写英文字符组成
//执行用时: 1304 ms
//内存消耗: 6.7 MBclass Solution {
public:
int strStr(string haystack, string needle) {
if( needle.size() == 0 ) return 0;
int same = 0;
for( int i = 0 ; i < haystack.size() ; i++ ){
if( haystack[i] == needle[0] ){
same++;
int j = i;
int a = 0;
while( haystack[++j] == needle[++a] && a < needle.size() && j < haystack.size() ) same++;
}
if( same == needle.size() ) return i;
else same = 0;
}
return -1;
}
};
y总
class Solution {
public:
int strStr(string s, string p) {
if (p.empty()) return 0;
int n = s.size(), m = p.size();
s = ' ' + s, p = ' ' + p;
vector<int> next(m + 1);
for (int i = 2, j = 0; i <= m; i ++ ) {
while (j && p[i] != p[j + 1]) j = next[j];
if (p[i] == p[j + 1]) j ++ ;
next[i] = j;
}
for (int i = 1, j = 0; i <= n; i ++ ) {
while (j && s[i] != p[j + 1]) j = next[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == m) return i - m;
}
return -1;
}
};
581. 最短无序连续子数组
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。
请你找出符合题意的 最短 子数组,并输出它的长度。
示例 1:
输入: nums = [2,6,4,8,10,9,15]
输出: 5
**解释:**你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
示例 2:
输入: nums = [1,2,3,4]
**输出:**0
示例 3:
输入: nums = [1]
**输出:**0
提示:
- 1 <= nums.length <= 104
- -105 <= nums[i] <= 105
**进阶:**你可以设计一个时间复杂度为 O(n) 的解决方案吗?
//执行用时:36 ms, 在所有 C++ 提交中击败了31.87% 的用户
//内存消耗:28 MB, 在所有 C++ 提交中击败了5.04% 的用户
class Solution {
public:
int findUnsortedSubarray(vector<int>& nums) {
vector<int> tmp;
for(int i = 0 ; i < nums.size() ; i++ ){
tmp.push_back(nums[i]);
}
sort(tmp.begin(),tmp.end());
int i = 0 ,j = nums.size()-1;
while( i<=j && nums[i] == tmp[i] ) i++;
while( i<=j && nums[j] == tmp[j] ) j--;
a
return j-i+1;
}
};
27. 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以"引用"方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
示例 1:
输入: nums = [3,2,2,3], val = 3
输出: 2, nums = [2,2]
解释: 函数应该返回新的长度 2 , 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:
输入: nums = [0,1,2,2,3,0,4,2], val = 2
输出: 5, nums = [0,1,4,0,3]
解释: 函数应该返回新的长度 5 , 并且 nums 中的前五个元素为 0 , 1 , 3 , 0 , 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
提示:
- 0 <= nums.length <= 100
- 0 <= nums[i] <= 50
- 0 <= val <= 100
总结:
1.STL remove(nums.begin(), nums.end(), val)
list_name.remove(const value_type& value);
//执行用时:4 ms, 在所有 C++ 提交中击败了54.67% 的用户
//内存消耗:8.6 MB, 在所有 C++ 提交中击败了47.89% 的用户
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
return remove(nums.begin(), nums.end(), val) - nums.begin();
}
};
面试题 01.05. 一次编辑
字符串有三种编辑操作:插入一个字符、删除一个字符或者替换一个字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。
示例 1:
输入:
first = "pale"
second = "ple"
输出: True
示例 2:
输入:
first = "pales"
second = "pal"
输出: False
注意这里有个问题,size()前面需要加个(int) ,否则两数相减是一个乱数
问题原因:string类的size() length()函数返回的是 无符号数,无符号数和有符号数相比出的问题。但是负数的话转成无符号数的话就会非常大
//执行用时:4 ms, 在所有 C++ 提交中击败了70.32% 的用户
//内存消耗:6 MB, 在所有 C++ 提交中击败了87.43% 的用户
class Solution {
public:
bool oneEditAway(string first, string second) {
if(( first.size() == 0 && second.size() == 1 ) || first.size() == 1 && second.size() == 0 ){
return true;
}
else if( (int)first.size() - (int)second.size() >= 2 || (int)second.size() - (int)first.size() >= 2 ){
return false;
}
else if( first.size() == second.size() ){ //替换
int diff = 0;
for(int i = 0 ; i < first.size() ; i ++ ){
if( first[i] != second[i] )
diff++;
}
if( diff == 1 || diff == 0 ) return true;
else return false;
}
else if(first.size() - second.size() == 1 || (int)second.size() - (int)first.size() == 1 ){
if( first.size() < second.size()) swap(first,second);
int diff2 = 0;
for(int i = 0 , j = 0 ; i < first.size() && j < second.size() ; ){
if( first[i] == second[j] ){
i++;
j++;
continue;
}else{
i++;
diff2++;
continue;
}
}
if( diff2 == 0 || diff2 == 1 ) return true;
else return false;
}
return false;
}
};
15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c , 使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入: nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入: nums = []
输出:[]
示例 3:
输入: nums = [0]
输出:[]
提示:
-
0 <= nums.length <= 3000
-
-105 <= nums[i] <= 105
//执行用时:80 ms, 在所有 C++ 提交中击败了53.78% 的用户
//内存消耗:19.5 MB, 在所有 C++ 提交中击败了71.70% 的用户class Solution {
public:
//双指针
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int i = 0 ; i < nums.size() ; i++ ){
//如果和前面的一样,该情况已经考虑过,则继续下循环
if( i && nums[i] == nums[i-1] ) continue;
for( int j = i + 1 , k = nums.size() -1 ; j < k ; j++ ){
//如果和前面的一样,该情况已经考虑过,则继续下循环
if( j > i + 1 && nums[j] == nums[j-1]) continue;
while( j < k - 1 && nums[i] + nums[j] + nums[k-1] >= 0 ) k--;
if(nums[i] + nums[j] + nums[k] == 0 ){
res.push_back({nums[i],nums[j],nums[k]});
}
}
}
return res;
}
};
~双指针
更多历史精彩文章(篇幅过多,不一一列出):
(简历相关)
求职经验分享(1):一份合格的简历应该如何写?-CSDN博客(推荐)
求职经验分享(2):简历如何优化以及如何应对面试【后端篇】-CSDN博客
(项目亮点相关)
大厂面试官赞不绝口的后端技术亮点【后端项目亮点合集(1):Redis篇】-CSDN博客
大厂面试官赞不绝口的后端技术亮点【后端项目亮点合集(2)】-CSDN博客
(八股文)
大厂面试官问我:Redis处理点赞,如果瞬时涌入大量用户点赞(千万级),应当如何进行处理?【后端八股文一:Redis点赞八股文合集】_java中redis如何实现点赞-CSDN博客大厂面试官问我:布隆过滤器有不能扩容和删除的缺陷,有没有可以替代的数据结构呢?【后端八股文二:布隆过滤器八股文合集】_布隆过滤器不能扩容-CSDN博客
.........
(算法篇)
大厂面试:算法考前必看汇总(全)_大厂面试算法题-CSDN博客
感兴趣的小伙伴可以给个三连~