目录
【leetcode 题号:238. 除自身以外数组的乘积】【难度:中等】
下列程序的输出是( )
- #include<stdio.h>
- int main()
- {
- int a [12]= {1,2,3,4,5,6,7,8,9,10,11,12},*p[4],i;
- for(i=0;i<4;i++)
- p[i]=&a [i*3];
- printf("%d\n",p[3][2]);
- return 0;
- }
A: 上述程序有错误 B: 6 C: 8 D: 12
正确答案:D
p是一个指针数组,p[i] = &a[i*3]相当于是把数组a每3个一组分开并把每组的首地址存在p数组,此时p类似一个4行3列的
二维数组,p[3][2]就是4行第3个元素12
二维数组X按行顺序存储,其中每个元素占1个存储单元。若 X[4][4] 的存储地址为 Oxf8b82140 , X[9][9] 的存储地址为 Oxf8b8221c ,则 X[7][7] 的存储地址为( )
A: Oxf8b821c4 B: Oxf8b821a6 C: Oxf8b82198 D: Oxf8b821c0
假设每行有n个元素:

从上图直观的看出 X[9][9] 与 X[4][4] 相差 5n - 5 个元素,则有以下计算公式:
[9][9] - [4][4] = 21c-140=5n+5 (1)[7][7] - [4][4]=z- 140 =3n+3 (2)
(1)中相减为 DC 为16进制,转换为十进制为 220 算出 n 为 43;
(2)z = 3n + 3 + 140 = 3 * 43 + 3+ 0x140 = 0x84 + 0x140 = 0x1c4
以下哪个选项可以正确描述 sizeof(double) ( )
A: 一个整型表达式 B: 一个双精度型表达式 C: 一个不合法的表达式 D: 一种函数调用
正确答案:A
sizeof ————操作数的类型长度(以字节为单位)
sizeof是C语言中的一个操作符,不是函数调用,简单的说其作用就是返回一个对象或者类型所占的内存字节数,结果是无符
号整数,因此可以把它看作是整型表达式。所以选择A
拓展:sizeof()和strlen()的异同
sizeof和strlen的返回类型都是unsigned int类型。
sizeof是关键字,sizeof(X)统计的是X的大小,单位是字节。例如X是数组,则统计数组的大小(字符数组包含'\0');若X是内置类型,则计算内置类型的大小;若X是指针变量,则计算指针变量的大小,等等。
strlen是库函数,参数是一个指针,用于求字符串长度,遇到'\0'就停止,不计算'\0'。
下列代码运行后的结果是什么( )
- int main()
- {
- char a = 'a',b;
- printf("%c,", ++a);
- printf("%c\n", b = a++);
- return 0;
- }
A: b,b B: b,c C: a,b D: a,c
正确答案:A
变量a里边存的是字符'a',第一次输出先加加再输出,输出的是'b';
第二次输出的时候,a先赋值再加加,赋值给b的就是a原来的值,输出b的时候的还是'b'
拓展:
前置++:是先将变量的值加1,然后使用加1后的值参与运算
后置++:是先使用该值参与运算,然后再将该值加1
以下逗号表达式的值为( )
(x = 4 * 5 , x * 5) , x + 5;
A: 25 B: 20 C: 100 D: 45
正确答案:A
逗号表达式是从前到后依次计算子表达式,而其结果是最后一项的值,
此题去掉括号后的表达式,和原表达式是等价的,先计算4*5并赋值给x,x变为20,中间x*5并没有改变x的值,最后一项x+5值是25,也就是整个表达式的值
自除数 是指可以被它包含的每一位数整除的数。
例如,128 是一个 自除数 ,因为 128 % 1 == 0,128 % 2 == 0,128 % 8 == 0。
自除数 不允许包含 0 。给定两个整数 left 和 right ,返回一个列表,列表的元素是范围 [left, right] 内所有的 自除数 。
示例 1:
输入:left = 1, right = 22
输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22]
示例 2:输入:left = 47, right = 85
输出:[48,55,66,77]提示:
1 <= left <= right <= 104
题目传送门:OJ链接
思路:自除数的判断,数字的每一位都能被源数字整除,有了这个规则,咱们只需要循环获取一个数字的每一位,然后与源数字取模判断是否为 0 ,如果中间有任意一次不为 0 ,则表示不是自除数。接下来,只需要遍历数组中的每个元素,判断是否是自除数即可,如果是则加入到返回数组中。
- int* selfDividingNumbers(int left, int right, int* returnSize){
- int *ret = (int *)calloc(1000, sizeof(int));//动态申请足够大的空间用于存放返回的自除数
- *returnSize = 0;
- for (int i = left; i <= right; i++)
- {
- int num = i;
- while (num)
- {
- int a = num % 10;
- if (a == 0 || i % a != 0)//判断i自身与余数取模是否为0
- {
- break;
- }
- num /= 10;//计算余数
- }
- if (num == 0)
- {
- ret[(*returnSize)++] = i;//如果num==0表示通过了每一位数的取模判断,则i就是自除数
- }
- }
- return ret;
- }
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]提示:
2 <= nums.length <= 105
-30 <= nums[i] <= 30
保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内
题目传送门:OJ链接
思路:
将乘积分为两次进行
第一次先将每个位置左边的数据乘积计算出来放到返回数组中
第二次循环将对应位置右边的数据乘积计算出来与返回数组对应位置的左半边乘积相乘得到结果。
简单举例子,便于理解:
一个数组 int nums[] = {2, 3, 4}
解析:
int left = 1; right = 1;
计算本身左边乘积:
- 第0个元素左边的乘积:arr[0] = left; 然后计算第1位左侧乘积:left *= nums[0] -> left = 1 * 2
- 第1个元素左边的乘积:arr[1] = left; 然后计算第2位左侧乘积:left *= nums[1] -> left = 1 * 2 *3
- 第2个元素左边的乘积:arr[2] = left; 然后计算第3位左侧乘积 但是没有意义,第二个元素已经是末尾元素
- 一次循环完毕后,返回数组中每个元素存储的都是自己左侧元素的乘积。 arr[]中的值: [1, 2, 6]
计算右侧的乘积:(对应位置的左边进行乘积)
此时arr[0] arr[1] arr[2] 为左侧乘积
- 第2个元素的右侧乘积(与左侧相乘):arr[2] *= right; 然后计算第1位右侧乘积 right *= nums[2] -> right = 1 * 4
- 第1个元素的右边乘积(与左侧相乘): arr[1] *= right 然后计算第0位右侧乘积 right *= nums[1] -> right = 1 * 4 * 3
- 第0个元素的右边乘积(与左侧相乘): arr[0] *= right 然后计算第-1位右侧乘积 -1位已经不需要计算了
- 循环完毕后,返回数组中的每个元素都是其他元素的乘积了 arr[2] *= 1; arr[1] *= 4; arr[0] *= 12
上边的例子已经讲的非常清楚了,根据上边例子的逻辑,设计题目要求的代码
- int* productExceptSelf(int* nums, int numsSize, int* returnSize){
- int *ret = (int *)malloc(numsSize * sizeof(int));
- *returnSize = numsSize;
- int left = 1;
- int right = 1;
- //第一次循环,将当前位置左边的数字乘积填入返回数组中
- for (int i = 0; i < numsSize; i++)
- {
- ret[i] = left;// 1 nums[0] nums[0]*nums[1] num[0]*nums[1]*nums[2] ....
- left *= nums[i];
- }
- //第二次循环,对于返回数组的元素从后往前进行,每次乘以右边元素的乘积
- for (int i = numsSize - 1; i >= 0; i--)
- {
- ret[i] *= right;//最后一个成绩不需要乘以最后元素,乘以1就行
- right *= nums[i];//right变化:1 nums[end] nums[end]*nums[end-1] .....
- }
- return ret;
- }