☘前言☘
今天是九日集训第四天,我会记录一下学习内容和题解,争当课代表0.0.
注意!!!!题解的解法1是今天要掌握的解法,解法2是学有余力再研究,涉及到后面知识点0.0
链接:《LeetCode零基础指南》(第五讲) 指针
🧑🏻作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
⏳全文大约阅读时间: 20min
全文目录
🎁主要知识点梳理
📝指针的定义和操作
🚗1.指针和地址
指针就是地址,在计算机中所有执行用到的数据都放在一个位置,这个位置都有一个标识,也就是地址。在32位计算机中寻址空间就是32位也就是232。因为是按字节寻址所以刚好是
4GB
,而64位寻址空间有足足2^64这么大。
我们把内存中字节的编号称为地址
或者``指针。地址从0开始。
🍛2.指针的定义
在c语言中可以用一个变量存放指针,称为指针变量,他们的关系如图:
其中p是指针变量名,x为被指向的变量的变量名,0x000000FC就是x的地址啦。
🦪3.定义指针变量
定义指针变量和普通变量类似,只不过需要在变量名前加
*
。
我们平常的定义的方式为:int *p; char *p;
特别注意:
*
是加在变量名前。对于我们需要指针和普通变量的混合定义就可以如下的方法:int b, *p, a;
就定义了一个指针,两个普通变量!
🍣4.取地址
我们通过
&
来表示取地址符号,代码示例:char x = 'o'; char *p = &x;
这样p就拿到了x的地址。
🍤5.数组地址
昨天介绍数组的时候其实说过,数组名称表示的就是首地址。所以可以赋值给p。
int a[] = {5,2,0,1,3,1,4}; int *p = a;
这样p就拿到了数组的地址。
🍤6.解引用
解引用就是取地址的逆操作,就是根据地址拿到元素。用
*
实现int a; int *p = &a; int c = *p;
上面的程序就是将a的值赋给了c。
🍚7.内存申请
c语言中,利用
malloc
来申请内存,传入参数为申请内存的字节数。返回值为申请到的内存首地址。然后还需要进行强制转化才能使用。int *p = (int *) malloc (1024);
因为一个int一般是占4字节的,所以上面我们申请到的就是
256
个int的数组空间。
也可以换种写法,更通用一些。int *p = (int *) malloc(sizeof(int)*256);
这样写会让你程序健壮性更强,因为不同的计算机的int长度可能有些不一致。
🧂8.力扣的刷题范式
int *func(int *nums, int numsSize, int *returnSize) { int *ret = (int *)malloc( sizeof(int) * xxx ); // TODO *returnSize = xxx; return ret; }
🥙9.概念总结
名词 | 简介 | 相关符号 |
---|---|---|
指针 | 变量的地址 | int * |
取地址 | 变量->地址 | &a |
解引用 | 地址->变量 | *p |
数组首地址 | 用数组名表示 | nums |
范式 | 规范写法 | 看上面 |
🍗课后习题
1470. 重新排列数组
1470. 重新排列数组
题目描述
给你一个数组
nums
,数组中有2n
个元素,按[x1,x2,...,xn,y1,y2,...,yn]
的格式排列。
请你将数组按[x1,y1,x2,y2,...,xn,yn]
格式重新排列,返回重排后的数组。
思路
根据奇偶来选择对应的元素就好了。
int* shuffle(int* nums, int numsSize, int n, int* returnSize){
int *ret = (int *) malloc(numsSize*sizeof(int));
for(int i = 0; i < numsSize; ++i)
if(i & 1)
ret[i] = nums[n+i/2]; //奇数就是后半段的数据
else
ret[i] = nums[(i + 1)/2]; //偶数就是前半段的数据
*returnSize = numsSize;
return ret;
}
1929. 数组串联
1929. 数组串联
题目描述
给你一个长度为 n 的整数数组 nums 。请你构建一个长度为 2n 的答案数组 ans ,数组下标 从 0 开始计数 ,对于所有 0 <= i < n 的 i ,满足下述所有要求:
- ans[i] == nums[i]
- ans[i + n] == nums[i]
具体而言,ans 由两个 nums 数组 串联 形成。
返回数组 ans 。
思路
作弊一下,用memcpy直接拷贝对应的内存元素就完事了0.0
int* getConcatenation(int* nums, int numsSize, int* returnSize){
int *ans = (int *) malloc(2*numsSize*sizeof(int));
memcpy(ans,nums,numsSize*sizeof(int));
memcpy(&ans[numsSize],nums,numsSize*sizeof(int));
*returnSize = 2 * numsSize;
return ans;
}
1920. 基于排列构建数组
1920. 基于排列构建数组
题目描述
给你一个 从 0 开始的排列
nums
(下标也从 0 开始)。请你构建一个 同样长度 的数组ans
,其中,对于每个i(0 <= i < nums.length)
,都满足ans[i] = nums[nums[i]]
。返回构建好的数组 ans 。
从 0 开始的排列nums
是一个由0
到nums.length - 1
(0
和nums.length - 1
也包含在内)的不同整数组成的数组
思路
他让干嘛就干嘛呗,公式都给了不用白不用-.-
int* buildArray(int* nums, int numsSize, int* returnSize){
int *ans =malloc(sizeof(int)*numsSize);
*returnSize = numsSize;
for(int i = 0;i < numsSize;i++)
ans[i] = nums[nums[i]];
return ans;
}
1480. 一维数组的动态和
1480. 一维数组的动态和
题目描述
给你一个数组
nums
。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i])
。
请返回nums
的动态和。
思路
他让干嘛就干嘛呗,公式都给了不用白不用-.-
int* runningSum(int* nums, int numsSize, int* returnSize){
for(int i = 1; i < numsSize; ++i){
nums[i] += nums[i-1];
}
*returnSize = numsSize;
return nums;
}
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
思路
虽然可以多次进行左旋 ,但是太浪费时间了。所以可以利用反转。
其实左旋的话就相当于先全部反转,然后再将前半部分反转,后半部分反转就好了。
举个例子:abcdefg
->gfedcba
->gfedcab
->cdefgab
void Reverse(char *p, char *q){
if(!p || !q) return;
while(p < q){
*p = *p ^ *q;
*q = *p ^ *q;
*p = *p ^ *q;
p++;q--;
}
}
char* reverseLeftWords(char* s, int n){
int size = 0;
while(s[size]) size++;
Reverse(s,&s[size-1]);//全部反转
Reverse(&s[size - n],&s[size - 1]);//反转后半段
Reverse(s,&s[size - 1 - n]);//反转前半段
return s;
}
1108. IP 地址无效化
1108. IP 地址无效化
题目描述
给你一个有效的 IPv4 地址 address,返回这个 IP 地址的无效化版本。
所谓无效化 IP 地址,其实就是用 “[.]” 代替了每个 “.”。
思路
为了避免多次移动,所以从后往前加入元素。
char * defangIPaddr(char * address){
int len;
for(len = 0; address[len];++len);//计算长度
int count = 3;
char *ans = malloc(sizeof(char)*(len + count * 2 + 1));
ans[len + count*2] = 0;//加入结束符
for(int i = len - 1; i >= 0; --i){
if(address[i] != '.') ans[i + count*2] = address[i];//不等于点就直接加入
else{//等于点就加入[.]
ans[i + count*2] = ']';
ans[i + count*2 - 1] = address[i];
ans[i + count*2 - 2] = '[';
count--;
}
}
return ans;
}
剑指 Offer 05. 替换空格
剑指 Offer 05. 替换空格
题目描述
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
思路
和上面一样的,因为
%20
比空格长。所以从后往前插入。
char* replaceSpace(char* s){
int count = 0,size = 0;
for(int i = 0;s[i];i++){
if(s[i] == ' ') count++;
size++;
}
int p1 = size,p2 = size + 2*count;
char *ans = malloc(sizeof(char)*(p2 + 1 ));
while(p1 >= 0){
if(s[p1] != ' ') ans[p2--] = s[p1--];
else{
ans[p2--] = '0';
ans[p2--] = '2';
ans[p2--] = '%';
p1--;
}
}
return ans;
}
1365. 有多少小于当前数字的数字
1365. 有多少小于当前数字的数字
题目描述
给你一个数组
nums
,对于其中每个元素nums[i]
,请你统计数组中比它小的所有数字的数目。
换而言之,对于每个nums[i]
你必须计算出有效的j
的数量,其中j
满足j != i
且nums[j] < nums[i]
。
以数组形式返回答案。
思路
从后往前扫描,做统计插入就好了。
int* smallerNumbersThanCurrent(int* nums, int numsSize, int* returnSize){
int *ans = malloc(numsSize*sizeof(int));
for(int i = 0; i < numsSize; ++i){
int sum = 0;
for(int j = 0; j < numsSize; j++)
if(nums[i] > nums[j]) sum++;
ans[i] = sum;
}
*returnSize = numsSize;
return ans;
}
剑指 Offer 17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
思路
从后往前扫描,做统计插入就好了。
int* printNumbers(int n, int* returnSize){
*returnSize = (int) pow(10,n) - 1;
int *ans = (int *)malloc((*returnSize)*sizeof(int));
for(int i = 0; i < *returnSize; ++i)
ans[i] = i + 1;
return ans;
}
1389. 按既定顺序创建目标数组
1389. 按既定顺序创建目标数组
题目描述
给你两个整数数组 nums 和 index。你需要按照以下规则创建目标数组:
- 目标数组 target 最初为空。
- 按从左到右的顺序依次读取 nums[i] 和 index[i],在 target 数组中的下标 index[i] 处插入值 nums[i] 。
- 重复上一步,直到在 nums 和 index 中都没有要读取的元素。
请你返回目标数组。
题目保证数字插入位置总是存在。
思路
创建一个插入功能的函数,然后依次插入就好了。
void inserst(int *ans,int *size,int weizhi,int k){
//printf("%d %d",weizhi,*size);
int wei = (*size)++;
while(wei != weizhi) ans[wei] = ans[wei - 1],wei--;
ans[weizhi] = k;//插入
}
int* createTargetArray(int* nums, int numsSize, int* index, int indexSize, int* returnSize){
int *ans = malloc(sizeof(int) * numsSize);
*returnSize = 0;
for(int i = 0;i < indexSize;i++)
inserst(ans,returnSize,index[i],nums[i]);
return ans;
}
📑写在最后
今天完成了第四天的打卡,今天的算法笔记记录刚好也有指针,你说巧不巧,哈哈哈,我真不是故意的,但是真的推荐读一读,万字长文,请给出一定的时间。写完我放评论区置顶链接0.0