C语言之练习题
欢迎来到我的:世界
希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 !😊
目录
- 前言
- 内容
- 第一题:子数组最大平均数
- 第二题:回文数
- 第三题:找到两个单身狗
- 第四题:一道面试笔试题
- 总结
前言
内容
第一题:子数组最大平均数
OJ地址
思路:
暴力求解法:设置两个指针,从开头向后找k个数值求平均值,继续往后遍历,找出最大平均值;注意:可能会显示时间超时
滑动窗口法:可以先将0~k
个数值的看作是一个窗口,计算出这个窗口中的所有元素的和sum
,并且记录所有元素和的最大值maxsum
,再让这个窗口往后移动一个数字计算窗口的和最大值,依次类推,等窗口走完,将得到的最大和maxsum / k =最大的平均值
动图演示:
暴力求解法:
double findMaxAverage(int* nums, int numsSize, int k) {
//设置最大平均值:
double maxaverage=-10000;
double x=k;//把int类型的k转化为double类型
for(int i=0;i<=numsSize-k;i++)
{
double sum=0;
//往后找k个数值
for(int j=i;j<k+i;j++)
{
sum+=nums[j];
}
sum=sum/x;//求平均值
if( sum >maxaverage )
maxaverage=sum;//找出最大平均值
}
return maxaverage;
}
滑动窗口法:
double findMaxAverage(int* nums, int numsSize, int k) {
int maxsum = 0;
int sum = 0;
//设置窗口
for (int i = 0; i < k; i++) {
sum += nums[i];
}
maxsum = sum;
//窗口移动
for (int i = k; i < numsSize; i++) {
sum = sum - nums[i - k] + nums[i];
maxsum = fmax(sum, maxsum);//fmax函数是得出两者中的较大值
}
return (double)maxsum / k;//不要忘记强制类型转换
}
第二题:回文数
OJ地址
思路:
双指针法:将整形数值x
转化为字符串类型
,可以使用sprintf
函数,字符串可以运用两个指针进行前后同时遍历,只要不同就返回false
;
双指针法:
bool isPalindrome(int x) {
if(x<0)//凡是小于0的不可能是回文数
return false;
if(x==0)
return true;
//将整形类型转化为字符串类型
char arr [100];
sprintf(arr,"%d",x);
//计算整形的位数
int count=0;
while(x)
{
x/=10;
count++;
}
//设置两个指针进行前后遍历
int i=0;
int j=count-1;
//开始遍历找不同
while(i<j)
{
if(arr[i++]!=arr[j--])
{
return false;
}
}
return true;
}
第三题:找到两个单身狗
介绍:
在一串数组中找到单独的两个数字,其余数都是成对出现的;如:arr[6]={1,2,1,3,2,4}
两个单身狗存到诞生狗数组中dog[2]
:就是这样dog[2]={3,4}
;
思路:
运用位运算:按位异或操作,但是如果是按照一个单身狗的解题方法是不可以的,因为最后会有两个值不同,但是我们可以将这两个数拆开放在不同数组中不就解决了,但是怎么将这个数组分成两个数组呢? 又根据什么进行分法呢?:所以带着这两个问题我们继续向下看:
可以发现按位异或^
操作的规律:
如3(011)^4(100)=111
,其实就是将这两个数不同的位变成了1
如7(111)^6(110)=001
,就是将这两个数二进制位不同的变成的了1:
所以我们可以推出:可以根据这两个单独数的位将进行分组
,
如:如果在这个数组中arr[6]={1,2,1,6,2,4}
,两个单身狗6
4
,进行按位异或^
操作后6^4 = 010
这代表6
和4
的二进制位从右边数第j=2
位不一样,让每个数的第j
位&
上1
就可以分别出他们,可以根据这点将这两个单独的数分开。
如图:
代码实现:
void Findalone(int arr[], int n)
{
int a = 0;
for (int i = 0; i < n; i++)
{
a ^= arr[i];
}
int num1[100] = { 0 };
int num2[100] = { 0 };
//找到二进制第j位上不同;
int j = 0;
for (j = 0; j < 32; j++)
{
//找到从右边数第j位,后直接跳出循环
if ( (a >> j) == 1)
break;
}
//创建两个指针分别遍历两个数组
int q1 = 0;
int q0 = 0;
//二进制的j位,不同的分成两个数组中,
// 就可以将两个单独的数分离开,再去分别求每个数组的单独数
for (int i = 0; i < n; i++)
{
if (((arr[i] >> j) & 1 )== 1)
{
num1[q1++] = arr[i];
}
else
{
num2[q0++] = arr[i];
}
}
//运用找单身狗的方法,找单独数
int k = 0;
for (int i = 0; i < q1; i++)
{
k ^= num1[i];
}
printf("其中一个单身狗是:%d\n", k);
k = 0;
for (int i = 0; i < q0; i++)
{
k ^= num2[i];
}
printf("另一个单身狗是:%d\n", k);
}
第四题:一道面试笔试题
请问该段代码输出的结果是什么?:
思路:
这题看似很复杂,其实很复杂 * _ *
先进行分析:一级指针数组c
,里面应该存存了四个地址,地址存放的是对应的字符串。(地址就是指针)
再分析二级指针数组cp
:二级指针存放了四个一级指针的地址,指针指向如图所示:
>再分析三级指针cpp
三级指针比较特殊,其存放一个地址,存放了二级指针cp
地址;>如图:
开始分析第一个语句:
printf("%s\n", **++cpp);
首先优先级:* < ++
, 关于优先级:只需要记住:++
,--
,()
,[]
的优先级就是最高的;
所以这里++
先和cpp结合,在进行解引用操作*
,
所以**++cpp 相当于 *(*(++cpp))
,++cpp相当于(cp+1);
然后解引用操作*
:就是根据这块地址找到这块地址所存的内容
第一个解引用操作*(++cpp)
找到cp数组的第二个元素(其中每一个元素都是一个二级指针地址)所存的内容是c数组的第三个元素;
第二次解引用*(*(++cpp))
就是指c数组的第三个元素中所存的内容:字符串“POINT”的首元素地址,所以最后打印就是打印从开头打印:POINT
printf("%s\n", **++cpp);
结果为POINT
分析第二个语句:
printf("%s\n", *-- * ++cpp + 3);
可看成这样:(*(--*(++cpp))) - 3
注意此时cpp应该是指向cp数组的第二个元素,*(++cpp)
此时cpp指针往后走一步后到cp数组的第三个元素,再进行解引用,根据cp第三个元素的地址,找到c数组中第二个元素,在看*(--*(++cpp))
先执行--
操作,此时又指向c数组第一个元素,在进行解引用,找到字符串ENTER
首元素地址,此时还没结束,还要+3
操作,就是从字符串往后找三个字节,找到了E
,所以此时打印就打印出ER
;
printf("%s\n", *-- * ++cpp + 3);
结果为ER
开始分析第三句话:
printf("%s\n", *cpp[-2] + 3);
注意此时cpp开始就指向cp数组的第三个元素;
看到cpp[-2] 就等于*(cpp-2)
该操作下来,应该为:cpp移动后指向cp的第一个元素,在进行解引用,找到了c数组的第四个元素,此时再进行解引用找到了字符串FIRST
,在进行+3
就是和上面的操作一样,找到字符S
,就从S
开始打印,出:ST
printf("%s\n", *cpp[-2] + 3);
结果为ST
分析最后一句话:
printf("%s\n", cpp[-1][-1] + 1);
看到cpp[-1][-1] 就等于 *(*(cpp-1)-1)
,操作步骤为-1
操作后cpp指向cp数组的第二个元素,解引用找到c数组第三个元素,在-1
操作后,指向c数组的第二个元素,解引用找打字符串NEW
,在进行+1
操作,找到字符E
,就从E开始打印出:EW
printf("%s\n", cpp[-1][-1] + 1);
结果为:EW
总结
到了最后:感谢支持
我还想告诉你的是:
------------对过程全力以赴,对结果淡然处之
也是对我自己讲的