【代码的暴力美学】-- C语言基础编程题_2
🔥个人主页:K 旺仔小馒头
🍉学习方向:C/C++方向学习者
📖个人专栏:《C语言》《数据结构与算法》《C++知识分享》《C语言实战编程》
⭐️人生格言:“何时葡萄先熟透,你要静候再静候”
前言:
本文围绕三个编程问题展开,涵盖等差数列求和、负整数统计与正整数均值计算,以及旋转数组最小值查找。结合数学公式与算法思维,解析如何把理论转化为高效代码,助力编程学习者提升实践能力。
一. 等差数列【难度:简单】
描述
对于首项为 2,公差为 3 的等差数列,求前 𝑛 项的和。
输入描述:
输入一个整数 𝑛(1≦𝑛≦10^3)。
输出描述:
输出一个整数,代表前 𝑛 项的和。
解析:
这道题了解了等差数列求和公式 Sn=n(a1+an)/2 就简单了,根据题目得知 a1=2,而等差数列第n项也有具体公式 an=a1+(n-1)d,而公差为3,这时候只需要套入公式计算即可。
#include <stdio.h>int main() {int n = 0;scanf("%d",&n);int a1 = 2;int sum = 0;sum = ((a1 + a1+3*(n-1))*n)/2;printf("%d",sum);return 0;
}
二. 记负均正【难度:简单】
描述
对于给定的 𝑛 个整数 𝑎1,𝑎2,⋯ ,𝑎𝑛,统计并计算:
∙ 负整数的个数;
∙ 正整数的平均值。
输入描述:
第一行输入一个整数 𝑛(1 ≦ 𝑛 ≦ 2×10^3) 代表整数的个数。
第二行输入 𝑛 个整数 𝑎1,𝑎2,…,𝑎𝑛(−10^3 ≦ 𝑎𝑖 ≦ 10^3) 代表输入的整数。
输出描述:
先输出一个整数,代表负整数的个数;随后在同一行输出一个实数,代表正整数的平均值。
由于实数的计算存在误差,当误差的量级不超过 10^−6时,您的答案都将被接受。具体来说,设您的答案为 𝑎 ,标准答案为 𝑏 ,当且仅当 ∣𝑎−𝑏∣ / max(1,∣𝑏∣) ≦ 10^−6 时,您的答案将被接受。
解析:
1. 输入处理:使用 scanf 读取整数个数 n ,然后循环读取 n 个整数。
2. 统计与计算:遍历每个整数,统计负整数的个数 count1;对正整数,累加其和 sum 并统计正整数的个数 count2。
3. 输出结果:计算正整数的平均值(若没有正整数则平均值为0),并按照要求输出负整数个数和保留六位小数的平均值。
#include <stdio.h>int main()
{int n = 0;scanf("%d",&n);//整数的个数int count1 = 0;//负整数的个数int count2 = 0;//正整数的个数double sum = 0;//正整数的总和int tmp = 0;//输入的整数for(int i = 0;i < n;i++){scanf("%d",&tmp);if(tmp > 0){sum += tmp;count2++;}else if(tmp < 0){count1++;}}double avg = count2 != 0 ? sum/count2 : 0.0;printf("%d %.6f",count1, avg);return 0;
}
三. 旋转数组的最小数字【难度:简单】
描述
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
数据范围:1≤𝑛≤10000,数组中任意元素的值: 0≤𝑣𝑎𝑙≤10000
要求:空间复杂度:𝑂(1) ,时间复杂度:𝑂(𝑙𝑜𝑔𝑛)
解析:
1. 暴力破解:遍历数组找出最小值即可
2. 更优思想:采用二分查找
这个题主要分析三种旋转情况 [1, 2, 3, 4, 5],使用中间值与右端进行比较。
a. 中间大于右边 [3, 4, 5, 1, 2],这种情况下,最小数一定在右边;则left = mid + 1
b. 中间等于右边 [1, 0, 1, 1, 1], 这个是[0, 1, 1, 1, 1] 旋转过来的,这时候需要缩小范围right--;注意不能是 left++,因为是非降序数组,所以要缩小右边范围,把较小值向右推,符合我们的判断规则。
c. 中间小于右边 [5, 1, 2, 3, 4], 这种情况下,最小数字则在左半边;则right = mid
知识点:二分查找
取中间位置索引:
left + (right - left) / 2 和 (left + right) / 2 这两种写法,最终计算得到的“中间位置索引”是完全一致的,都是为了在二分查找中找到左右区间的中间点,从而缩小查找范围。
而 left + (right - left) / 2 之所以更“安全”,核心就是避免了 left 和 right 直接相加时可能出现的整数溢出问题(比如当 left 和 right 本身很大,两者相加超过了整数类型的最大值时,用 (left + right) / 2 就会出错,而 left + (right - left) / 2 能规避这种情况)。
简单来说,二者“找中间点”的目标是一样的,只是 left + (right - left) / 2 在工程实践中更健壮~
注意:这个题目在牛客网里编译的话,你不用写main函数哈,别人会调用minNumberInRotateArray这个函数的(这个就相当于main函数);如果你再写一个main函数,就会报错(报错原因:有多个main函数)
牛客网里是这么给的代码,不需要再额外加main函数
int minNumberInRotateArray(int* nums, int numsLen ) {// write code here //你只要在这里添加代码就好 }
int minNumberInRotateArray(int* nums, int numsLen)
{int left = 0;int right = numsLen - 1;while (left < right) {int mid = left + (right-left)/2;if(nums[mid] > nums[right]){left = mid + 1;}else if(nums[mid] < nums[right]){right = mid;}else {right--;}}return nums[left];
}
结尾:
往期精选:
【代码的暴力美学】-- C语言基础编程题_1
结语:
文中三个编程问题的解法,体现了数学与算法在编程中的巧妙结合。从基础公式运用到复杂查找的优化,为编程学习者提供了将知识转化为高效代码的范例,期望能启发大家在编程之路上不断探索。