C 语言初阶算法习题实战解析(二)
在算法学习的初级阶段,掌握基础的数据处理逻辑至关重要。下面整理了五道经典的 C 语言算法题,涵盖数组操作、字符串处理及位运算技巧,结合代码实现与思路解析,希望能帮助大家巩固基础。
一、两数之和
题目描述:
给定一个整数数组 numbers 和一个目标值 target,请在数组中找出和为目标值的两个整数,并返回它们的下标(从 1 开始计数)。

核心思路: 这道题采用双重循环的暴力解法即可解决。外层循环遍历数组中的每个元素,内层循环查找与其相加等于目标值的另一个元素。需要注意的是,题目要求返回的下标是从 1 开始的,所以存储结果时需要将索引加 1。如果当前元素已经大于目标值,可以直接跳过,因为后续元素只会更大(假设数组有序或基于此优化),不过通用解法中直接判断和是否相等更稳妥。
参考代码如下:
int *twoSum(int *numbers, int numbersLen, int target, int *returnSize) {
// 动态分配结果数组
int *ret = (int *)malloc(sizeof(int) * numbersLen);
for (int i = 0; i < numbersLen; i++) {
if (numbers[i] > target) {
continue;
}
for (int j = i + 1; j < numbersLen; j++) {
int sum = numbers[i] + numbers[j];
if (sum == target) {
ret[0] = i + 1;
ret[1] = j + 1;
*returnSize = 2;
return ret;
}
}
}
return 0;
}
二、珠玑妙算
题目描述: 根据猜谜游戏的规则,计算完全匹配(位置和内容都对)和部分匹配(内容对但位置不对)的数量。

核心思路: 我们需要两次遍历来解决这个问题。第一次遍历专门统计'完全匹配'的情况,即相同位置的字符一致。为了避免重复计算,一旦匹配成功,就将这两个位置的字符标记为特殊字符(如 '0')。第二次遍历则用于统计'部分匹配',此时只检查未被标记的字符是否在另一串中出现过,同样需要标记已匹配的字符以防重复。
参考代码如下:
int *masterMind(char *solution, char *guess, int *returnSize) {
int *ret = (int *)malloc(sizeof(int) * 2);
ret[0] = 0;
ret[1] = 0;
int len = strlen(solution);
// 第一次遍历:统计完全匹配
for (int i = 0; i < len; i++) {
if (solution[i] == guess[i]) {
ret[0]++;
solution[i] = guess[i] = '0';
}
}
// 第二次遍历:统计部分匹配
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
if (solution[i] == guess[j] && solution[i] != '0') {
ret[1]++;
solution[i] = guess[j] = '0';
break;
}
}
}
*returnSize = 2;
return ret;
}
三、寻找奇数
题目描述: 在一个数组中,除了一个数字外,其余的数字都出现了两次。请找出那个只出现一次的数字。

核心思路: 利用异或运算的特性可以非常高效地解决这个问题。任何数字与自身异或结果为 0,与 0 异或结果为自身本身。因此,将数组中所有数字依次进行异或运算,成对出现的数字会相互抵消,最终剩下的就是那个唯一的数字。
参考代码如下:
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int ret = 0;
int m = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &m);
ret ^= m;
}
printf("%d\n", ret);
return 0;
}
四、截取字符串
题目描述: 给定一个字符串和一个截断长度,输出该字符串的前 N 个字符。

核心思路:
实现字符串截取主要有两种方式:一是使用标准库函数 strncpy,二是手动将指定位置的字符修改为字符串结束符 \0。第二种方法更直观且性能开销更小,适合简单的场景。
参考代码如下:
// 方法一:使用 strncpy
int main() {
char str[100];
scanf("%s", str);
int n;
scanf("%d", &n);
char ret[100];
strncpy(ret, str, n);
ret[n] = '\0';
printf("%s\n", ret);
return 0;
}
// 方法二:直接修改结束标志
int main() {
char str[1000];
scanf("%s", str);
int n = 0;
scanf("%d", &n);
str[n] = '\0';
printf("%s\n", str);
return 0;
}
五、寻找峰值
题目描述: 给定一个整数数组,找到任意一个峰值元素的索引。峰值元素是指其值大于左右相邻值的元素。

核心思路: 首先处理边界情况,如果第一个元素大于第二个,或者最后一个元素大于倒数第二个,它们本身就是峰值。然后遍历中间的元素,检查是否满足大于左右邻居的条件。如果没有找到,返回 -1。
参考代码如下:
int findPeakElement(int *nums, int numsLen) {
// 找两端的峰值
if (nums[0] > nums[1]) {
return 0;
}
if (nums[numsLen - 1] > nums[numsLen - 2]) {
return numsLen - 1;
}
for (int i = 1; i < numsLen - 1; i++) {
if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
return i;
}
}
return -1;
}
以上便是本期整理的算法习题,建议大家在本地环境多运行几遍,熟悉不同场景下的边界处理。

