既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
### 顺序表扩容
>
> 面对空间已满,没法再插入数据的情况,需要增容
>
>
>
//扩容
void SeqListCreate(SeqList *ps)
{
assert(ps);
//空间满了开辟一块新的空间
if (ps->capacity == ps->size)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
int *newA = (int *)realloc(ps->arr, sizeof(int) * newcapacity);
if (newA == NULL)
{
perror(“SeqListCreate:”);
exit(1);
}
ps->arr = newA;
ps->capacity = newcapacity;
}
}
### 顺序表的头插
>
> 头插数据需要考虑是从前往后挪动数据还是从后往前挪动数据,很明显如果是从前往后挪动数据的话,会将原有的数据给覆盖掉,所以只能从后往前,头插的时间复杂度是o(n)
>
>
>
//头插
void SeqListPushFront(SeqList *ps,int x)
{
assert(ps);
SeqListCreate(ps);
int end = ps->size - 1;
//从后往前挪动数据
while (end >= 0)
{
ps->arr[end + 1] = ps->arr[end];
end–;
}
//头插数据
ps->arr[0] = x;
ps->size++;
}
### 顺序表的尾插
>
> 其实顺序表的尾插,时间复杂度o(1)
>
>
>
//尾插
void SeqListPushBack(SeqList *ps,int x)
{
assert(ps);
SeqListCreate(ps);
ps->arr[ps->size++] = x;
}
### 顺序表的遍历打印
>
> 遍历顺序表,o(n)的时间复杂度
>
>
>
//打印
void SeqListprint(SeqList * ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
printf("%d ",ps->arr[i]);
}
}
### 顺序表的尾删
>
> 这里要考虑的是需要判断表中有没有数据,如果没有数据就不需要删除
>
>
>
//尾删
void SeqListPopBack(SeqList *ps)
{
assert(ps);
assert(ps->size > 0);
ps->size–;
}
### 顺序表的头删
>
> 将后一个数据覆盖掉前一个数据,最后- -size,因为需要挪动数据所以时间复杂度是o(n)
>
>
>
//头删
void SeqListPopFront(SeqList *ps)
{
assert(ps);
assert(ps->size > 0);
int begin = 0;
while (begin < ps->size)
{
ps->arr[begin] = ps->arr[begin + 1];
begin++;
}
ps->size–;
}
### 顺序表的查找
>
> 找到返回该位置的下标,O(N)时间复杂度
>
>
>
//查找
int SeqListFind(SeqList * ps, int x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
return i;
}
}
return -1;
}
### 删除
>
> 删除指定pos位置的元素,可以挪动数据将其覆盖,从前往后的覆盖法,挪动数据时间复杂度O(N)
>
>
>
//删除
void SeqListErase(SeqList *ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos;
while (begin < ps->size)
{
ps->arr[begin] = ps->arr[begin + 1];
++begin;
}
ps->size–;
}
### 插入
>
> 将pos位置和pos后的数据整体往后一挪动,再将x插入到指定pos位置,注意选择的位置不能超出顺序表的大小
> 时间复杂度O(N)
>
>
>
void SeqListInsert(SeqList *ps, int pos, int x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
SeqListCreate(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->arr[end + 1] = ps->arr[end];
end–;
}
ps->arr[pos] = x;
ps->size++;
}
### 修改
>
> 修改该位置的值
>
>
>
void SeqListmodif(SeqList *ps, int pos, int x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
ps->arr[pos] = x;
}
## 顺序表的问题及思考:
1、顺序表的指定插入和删除都需要挪动数据,时间复杂度为O(N)
2、增容需要申请空间,拷贝数据,释放就空间,会有不小的消耗,一定程度上也会影响效率,增容会存在空间浪费,开大了浪费,开小了又不够
## 力扣题
### 27. 移除元素:
[点我](https://bbs.csdn.net/topics/618668825).
![在这里插入图片描述](https://img-blog.csdnimg.cn/67574c9ed20f4ef3bd5ba9ca47ed93a4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
**思路一:**
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入,找出值为val的位置挪动后面的数据覆盖掉val的值,
时间复杂度是0(N\*N),考虑最坏的情况如果数组中的值全是val的话,每次找出一个值为val的时间复杂度是o(N),挪动数据又是o(N),整体就是O(N \* N)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b4f3ade34d694410b464a01f374a2645.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_16,color_FFFFFF,t_70,g_se,x_16)
**思路二:**
开辟一个空间足够大的数组,遍历一遍找出原数组将值不为val的,拷贝到新数组中去,时间复杂度是O(N),空间复杂度是O(N)。空间换时间
**思路三:**
双指针解法,在原数组的基础上创建一个虚拟数组,src和dest都从0开始,src去找值不为val的,找到后将src位置的值覆盖掉dest位置的值,他们都自增,如果src的值等于val,src就继续找,最后返回dest,时间复杂度是O(N),空间复杂度是O(1),
![在这里插入图片描述](https://img-blog.csdnimg.cn/0741d398ed4349a3bd3902d9dbe1a856.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
int removeElement(int* nums, int numsSize, int val){
if(numsSize == 0)
return 0;
int dest = 0;
int src = 0;
while(src < numsSize)
{
if(nums[src] != val)
{
nums[dest++] = nums[src++];
}
else
{
src++;
}
}
return dest;
}
### 26. 删除有序数组中的重复项:
[点我](https://bbs.csdn.net/topics/618668825).
![在这里插入图片描述](https://img-blog.csdnimg.cn/b08901e308ab4f2987fe2e0aa26dc07b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
**解题思路:**
src和next一前一后,如果src的值不等于dst,就将src的值覆盖在dst的位置上,dst++,next的位置赋值给src,next++找下一个数,在回来判断next位置的值是否与src相等,如果相等继续执行,直到条件为假循环终止
时间复杂度是O(N),空间复杂度是O(1)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20e0b53abb204f1cace9db9d44364fd0.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
考虑这种情况,如果next已经 > numsize了,循环终止,但是末尾的那个元素还没有拷贝过来
![在这里插入图片描述](https://img-blog.csdnimg.cn/47c09bd674e042f1b2e8bc78eafa2b6f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
int removeDuplicates(int* nums, int numsSize){
if(numsSize == 0)
{
return 0;
}
int cur = 0;
int next = 1;
int count = 0;
int dest = 0;
while(next < numsSize)
{
//cur和next将重复的值给过滤掉,只留下一个值给dst
if(nums[cur] != nums[next])
{
nums[dest++] = nums[cur];
cur = next;
++next;
}
else
{
++next;
}
}
//防止循环终止后,最后一个数据丢失
if(cur < numsSize)
nums[dest++] = nums[cur];
return dest;
}
### 27. 数组形式的整数加法:
28. [点我](https://bbs.csdn.net/topics/618668825).
. ![在这里插入图片描述](https://img-blog.csdnimg.cn/653f9da8da794b9994026e3591f3b8f1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
**测试用例**
![在这里插入图片描述](https://img-blog.csdnimg.cn/2109da90ea364a26aa63e92090d34366.png)
>
> 解题思路:
> 计算出val的十进制位数,取val或数组长度大的那一个作为新数组的大小(存在进位问题),继续将val的每一位取下来对应的个位、十位、百位…看成与数组元素的一种关联关系,通过不断拆分相加它们之间的和,和值大于10就考虑进位,小于10不进位,最后将这两个值相加得到的和存放到对应的位置上,由于是从低位开始计算的,存在数组的顺序也是倒过来的,所以再最后需要整体一逆转
>
>
>
int* addToArrayForm(int* A, int numSize, int k, int* returnSize){
int ksize = 0;
int num = k;
//记录num的十进制位数
while(num)
{
num /= 10;
++ksize;
}
int reti = 0;
//扩容一位提供进位
int len = numSize > ksize ? numSize + 1 : ksize + 1;
int Ai = numSize - 1;
int ki = 0;
int next = 0;//进位
int \*retArr = (int \*)malloc(sizeof(int) \* len);
while(Ai >= 0 || ki < ksize)
{
int aval = 0;
if(Ai >= 0)
aval = A[Ai--];
int kval = k % 10;
k /= 10;
ki++;
int ret = kval + aval + next;
if(ret >= 10)
{
next = 1;
ret -= 10;
}
else
{
next = 0;
}
retArr[reti++] = ret;
}
//存放最高位
if(next == 1)
{
retArr[reti++] = 1;
}
//逆置数组
int begin = 0;
int end = reti - 1;
while(begin < end)
{
int tmp = retArr[begin];
retArr[begin] = retArr[end];
retArr[end] = tmp;
begin++;
end--;
}
\*returnSize = reti;
return retArr;
}
### 旋转数组:
[点我](https://bbs.csdn.net/topics/618668825).
![在这里插入图片描述](https://img-blog.csdnimg.cn/055e9233a72448c5b15ee8e07f53825c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
>
> 解题思路:
> 将数组整体旋转一次,以k为划分左旋转0 ~ k - 1这个区间,
> 右旋转k ~ numsize - 1区间,整体就是旋转k次的数组,有点类似于左旋转字符串,时间复杂度是O(N + N),还是O(N)
> ![在这里插入图片描述](https://img-blog.csdnimg.cn/9bab310a91f4453da1bfa368f37df72e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASVTojqvmiY7nibk=,size_20,color_FFFFFF,t_70,g_se,x_16)
>
>
>
//逆置数组
void reverse(int* nums1,int *nums2)
{
while(nums1 < nums2)
{
int tmp = *nums1;
*nums1 = *nums2;
*nums2 = tmp;
++nums1;
--nums2;
}
}
void rotate(int* nums, int numsSize, int k){
if(k >= numsSize)
k %= numsSize;
//整体旋转
reverse(nums, nums + numsSize - 1);
//左旋转
reverse(nums,nums + k - 1);
//右旋转
reverse(nums + k,nums + numsSize - 1);
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
t* nums, int numsSize, int k){
if(k >= numsSize)
k %= numsSize;
//整体旋转
reverse(nums, nums + numsSize - 1);
//左旋转
reverse(nums,nums + k - 1);
//右旋转
reverse(nums + k,nums + numsSize - 1);
[外链图片转存中…(img-zR5uxVRv-1715733485682)]
[外链图片转存中…(img-9jIwBSfw-1715733485682)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新