1.编写一个程序,找出一个整数数组中的最大值和最小值。要求使用函数实现,并在主函数中进行调用。
答案:
#include <stdio.h>
void findMinMax(int arr[], int size, int *min, int *max) {
*min = *max = arr[0]; // 初始化最小值和最大值为数组的第一个元素
for (int i = 1; i < size; i++) {
if (arr[i] < *min) {
*min = arr[i]; // 更新最小值
}
if (arr[i] > *max) {
*max = arr[i]; // 更新最大值
}
}
}
int main() {
int arr[] = {5, 3, 9, 1, 7};
int size = sizeof(arr) / sizeof(arr[0]);
int min, max;
findMinMax(arr, size, &min, &max);
printf("最小值:%d\n", min);
printf("最大值:%d\n", max);
return 0;
}
解析:
这道题要求编写一个函数 findMinMax
来找出给定整数数组中的最大值和最小值,并在主函数中调用该函数。在 findMinMax
函数中,我们使用两个指针变量 min
和 max
来保存最小值和最大值。我们首先将它们初始化为数组的第一个元素 arr[0]
,然后遍历数组的剩余元素。对于每个元素,我们比较它是否小于 min
,如果是,则更新 min
的值;比较它是否大于 max
,如果是,则更新 max
的值。最后,在主函数中,我们声明了一个整数数组 arr
并初始化它,然后计算数组的大小。接下来,我们声明了两个变量 min
和 max
,它们用于保存最小值和最大值。然后,我们调用 findMinMax
函数,并传递数组 arr
、数组大小以及 min
和 max
的地址作为参数。最后,我们在主函数中打印出最小值和最大值的结果。
这道题考察了对函数的使用和指针的理解。通过将指针作为参数传递给函数,我们可以在函数内部修改变量的值,并将结果返回给调用者。在主函数中,我们通过传递指针来获取函数计算的最小值和最大值。
2.编写一个程序,接受用户输入的一个字符串,统计并输出字符串中的字母、数字和其他字符的个数。
答案:
#include <stdio.h>
#include <ctype.h>
void countCharacters(char *str, int *letters, int *digits, int *others) {
*letters = *digits = *others = 0; // 初始化字母、数字和其他字符的计数器为0
while (*str != '\0') {
if (isalpha(*str)) {
(*letters)++; // 字母计数器加1
} else if (isdigit(*str)) {
(*digits)++; // 数字计数器加1
} else {
(*others)++; // 其他字符计数器加1
}
str++; // 移动到下一个字符
}
}
int main() {
char str[100];
printf("请输入一个字符串:");
fgets(str, sizeof(str), stdin);
int letters, digits, others;
countCharacters(str, &letters, &digits, &others);
printf("字母个数:%d\n", letters);
printf("数字个数:%d\n", digits);
printf("其他字符个数:%d\n", others);
return 0;
}
解析:
这道题要求编写一个函数 countCharacters
来统计给定字符串中的字母、数字和其他字符的个数,并在主函数中调用该函数。在 countCharacters
函数中,我们使用三个指针变量 letters
、digits
和 others
来保存字母、数字和其他字符的个数。我们首先将这三个计数器初始化为0。然后,我们使用一个循环遍历字符串中的每个字符。对于每个字符,我们使用 isalpha
函数判断它是否是字母,如果是,则将字母计数器加1;使用 isdigit
函数判断它是否是数字,如果是,则将数字计数器加1;否则,将其他字符计数器加1。最后,在主函数中,我们声明了一个字符数组 str
来接受用户输入的字符串,并使用 fgets
函数读取用户输入。然后,我们声明了三个变量 letters
、digits
和 others
,用于保存字母、数字和其他字符的个数。接下来,我们调用 countCharacters
函数,并传递字符串 str
和计数器变量的地址作为参数。最后,我们在主函数中打印出字母个数、数字个数和其他字符个数的结果。
这道题考察了字符串处理和字符分类函数的使用。通过遍历字符串中的每个字符,并使用相应的函数判断字符的类型,我们可以统计出字符串中字母、数字和其他字符的个数。
3.编写一个程序,接受用户输入的一个正整数n,计算并输出n的阶乘。
答案:
#include <stdio.h>
unsigned long long factorial(unsigned int n) {
if (n == 0 || n == 1) {
return 1; // 0的阶乘和1的阶乘均为1
} else {
unsigned long long result = 1;
for (unsigned int i = 2; i <= n; i++) {
result *= i; // 逐步累乘得到阶乘
}
return result;
}
}
int main() {
unsigned int n;
printf("请输入一个正整数:");
scanf("%u", &n);
unsigned long long result = factorial(n);
printf("%u的阶乘:%llu\n", n, result);
return 0;
}
解析:
这道题要求编写一个函数 factorial
来计算给定正整数n的阶乘,并在主函数中调用该函数。在 factorial
函数中,我们使用一个循环从2到n,逐步累乘得到n的阶乘。我们首先判断特殊情况,如果n为0或1,则阶乘结果为1。否则,我们初始化一个变量 result
为1,然后使用循环从2开始迭代到n,将每个数乘以 result
,最终得到n的阶乘。在主函数中,我们声明了一个无符号整数变量 n
,用于接受用户输入的正整数。然后,我们调用 factorial
函数,并传递 n
作为参数,将计算得到的阶乘结果保存在变量 result
中。最后,我们在主函数中打印出输入的正整数和计算得到的阶乘结果。
这道题考察了循环和函数的使用。通过使用循环逐步累乘,我们可以计算出给定正整数的阶乘。在主函数中,我们将用户输入作为参数传递给函数,并将计算结果输出。
4.编写一个程序,接受用户输入的一个整数n,判断该整数是否为素数(质数)。若是素数,则输出"是素数";否则输出"不是素数"。
答案:
#include <stdio.h>
int isPrime(int n) {
if (n <= 1) {
return 0; // 小于等于1的数不是素数
}
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
return 0; // 存在能整除n的数,不是素数
}
}
return 1; // n没有能整除它的数,是素数
}
int main() {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
if (isPrime(n)) {
printf("%d是素数\n", n);
} else {
printf("%d不是素数\n", n);
}
return 0;
}
解析:
这道题要求编写一个函数 isPrime
来判断给定整数n是否为素数,并在主函数中调用该函数。在 isPrime
函数中,我们首先判断特殊情况,如果n小于等于1,则不是素数。然后,我们使用一个循环从2开始迭代到n的平方根,判断是否存在能整除n的数。如果存在能整除n的数,则n不是素数;否则,n是素数。在主函数中,我们声明了一个整数变量 n
,用于接受用户输入的整数。然后,我们调用 isPrime
函数,并传递 n
作为参数进行判断。根据函数返回的结果,我们在主函数中打印出相应的输出。
这道题考察了循环和条件判断的使用。通过使用循环判断n是否能被2到平方根范围内的数整除,我们可以确定n是否为素数。在主函数中,我们根据函数的返回结果输出相应的结果。
5.编写一个程序,接受用户输入的一个正整数n,计算并输出n行的杨辉三角形。
答案:
#include <stdio.h>
void printPascalTriangle(int n) {
int triangle[n][n];
// 初始化第一列和对角线上的元素为1
for (int i = 0; i < n; i++) {
triangle[i][0] = 1;
triangle[i][i] = 1;
}
// 填充其余元素
for (int i = 2; i < n; i++) {
for (int j = 1; j < i; j++) {
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
}
}
// 打印杨辉三角形
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) {
printf("%d ", triangle[i][j]);
}
printf("\n");
}
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
printPascalTriangle(n);
return 0;
}
解析:
这道题要求编写一个函数 printPascalTriangle
来计算并输出给定正整数n行的杨辉三角形,并在主函数中调用该函数。在 printPascalTriangle
函数中,我们首先声明一个二维数组 triangle
,用于保存杨辉三角形的元素。然后,我们使用两个循环进行填充操作。首先,我们初始化第一列和对角线上的元素为1,因为它们都是杨辉三角形的边界元素。然后,我们使用嵌套的循环来填充其余元素。对于每一行的第j个元素,它的值等于上一行的第j-1个元素和第j个元素的和。最后,我们使用另外两个嵌套的循环来打印杨辉三角形的元素。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 printPascalTriangle
函数,并将 n
作为参数进行计算和输出。
这道题考察了二维数组和嵌套循环的使用。通过使用二维数组来保存杨辉三角形的元素,并通过嵌套循环进行填充和打印操作,我们可以生成指定行数的杨辉三角形。
6.编写一个程序,接受用户输入的一个正整数n,判断并输出该整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都相同的数。
答案:
#include <stdio.h>
int isPalindrome(int n) {
int reversedNum = 0;
int originalNum = n;
while (n > 0) {
reversedNum = reversedNum * 10 + n % 10; // 反转数字
n /= 10;
}
if (reversedNum == originalNum) {
return 1; // 是回文数
} else {
return 0; // 不是回文数
}
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
if (isPalindrome(n)) {
printf("%d是回文数\n", n);
} else {
printf("%d不是回文数\n", n);
}
return 0;
}
解析:
这道题要求编写一个函数 isPalindrome
来判断给定正整数n是否是回文数,并在主函数中调用该函数。在 isPalindrome
函数中,我们首先声明两个变量 reversedNum
和 originalNum
,其中 reversedNum
用于保存反转后的数字,originalNum
用于保存原始的输入数字n。然后,我们使用一个循环将n逐位反转。在每次循环中,我们将 reversedNum
乘以10并加上n的个位数,然后将n除以10,以便下一次循环处理十位数。最后,我们将反转后的数字 reversedNum
与原始的输入数字 originalNum
进行比较,如果相等,则n是回文数;否则,n不是回文数。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 isPalindrome
函数,并将 n
作为参数进行判断。根据函数的返回结果,我们在主函数中打印出相应的输出。
这道题考察了循环和数字反转的使用。通过将数字逐位反转,并与原始的输入数字进行比较,我们可以判断给定的正整数是否是回文数。
7.编写一个程序,接受用户输入的一个字符串,判断该字符串是否是回文字符串。回文字符串是指正序和倒序读都相同的字符串。
答案:
#include <stdio.h>
#include <string.h>
int isPalindrome(const char* str) {
int len = strlen(str);
int i = 0;
int j = len - 1;
while (i < j) {
if (str[i] != str[j]) {
return 0; // 不是回文字符串
}
i++;
j--;
}
return 1; // 是回文字符串
}
int main() {
char str[100];
printf("请输入一个字符串:");
scanf("%s", str);
if (isPalindrome(str)) {
printf("%s是回文字符串\n", str);
} else {
printf("%s不是回文字符串\n", str);
}
return 0;
}
解析:
这道题要求编写一个函数 isPalindrome
来判断给定字符串是否是回文字符串,并在主函数中调用该函数。在 isPalindrome
函数中,我们首先使用 strlen
函数获取字符串的长度。然后,我们使用两个指针 i
和 j
分别指向字符串的开头和结尾,并进行比较操作。在每次循环中,我们比较指针所指向的字符是否相等,如果不相等,则字符串不是回文字符串。如果相等,则将指针 i
向后移动一位,将指针 j
向前移动一位,继续进行下一轮的比较。当 i
大于等于 j
时,表示已经比较完字符串的一半,且字符都相等,字符串是回文字符串。在主函数中,我们声明一个字符数组 str
,用于接受用户输入的字符串。然后,我们调用 isPalindrome
函数,并将 str
作为参数进行判断。根据函数的返回结果,我们在主函数中打印出相应的输出。
这道题考察了字符串处理和指针的使用。通过使用两个指针从字符串的开头和结尾向中间移动,并比较对应的字符是否相等,我们可以判断给定的字符串是否是回文字符串。
8.编写一个程序,接受用户输入的一个整数n,计算并输出斐波那契数列的前n项。
答案:
#include <stdio.h>
void printFibonacciSeries(int n) {
if (n <= 0) {
return;
}
int first = 0;
int second = 1;
printf("斐波那契数列的前%d项:\n", n);
printf("%d ", first);
if (n >= 2) {
printf("%d ", second);
}
for (int i = 3; i <= n; i++) {
int next = first + second;
printf("%d ", next);
first = second;
second = next;
}
printf("\n");
}
int main() {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
printFibonacciSeries(n);
return 0;
}
解析:
这道题要求编写一个函数 printFibonacciSeries
来计算并输出斐波那契数列的前n项,并在主函数中调用该函数。在 printFibonacciSeries
函数中,我们首先判断特殊情况,如果n小于等于0,则不需要进行计算。然后,我们声明两个变量 first
和 second
,分别用于保存斐波那契数列的前两个数。我们先输出第一个数 first
,然后判断n是否大于等于2,如果是,则输出第二个数 second
。接下来,我们使用一个循环从第三个数开始计算并输出剩余的斐波那契数列。在每次循环中,我们计算下一个数 next
,并将其输出。然后,我们更新 first
和 second
的值,将 second
赋值给 first
,将 next
赋值给 second
,以便下一次循环的计算。最后,我们在每行数字之间输出空格,并在斐波那契数列结束后换行。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的整数。然后,我们调用 printFibonacciSeries
函数,并将 n
作为参数进行计算和输出。
这道题考察了循环和变量更新的使用。通过使用循环和变量更新来计算并输出斐波那契数列的前n项,我们可以生成指定数量的斐波那契数列。
9.编写一个程序,接受用户输入的一个整数n,计算并输出n的阶乘。
答案:
#include <stdio.h>
int calculateFactorial(int n) {
int factorial = 1;
if (n < 0) {
printf("输入的整数不能为负数。\n");
return -1;
}
for (int i = 1; i <= n; i++) {
factorial *= i;
}
return factorial;
}
int main() {
int n;
printf("请输入一个整数:");
scanf("%d", &n);
int result = calculateFactorial(n);
if (result != -1) {
printf("%d的阶乘为:%d\n", n, result);
}
return 0;
}
解析:
这道题要求编写一个函数 calculateFactorial
来计算给定整数n的阶乘,并在主函数中调用该函数。在 calculateFactorial
函数中,我们首先判断特殊情况,如果n小于0,则输入的整数无效,输出错误提示并返回-1。否则,我们声明一个变量 factorial
并将其初始化为1,用于保存阶乘的结果。然后,我们使用一个循环从1到n,将每个数字依次乘以 factorial
。最后,我们返回计算得到的阶乘值。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的整数。然后,我们调用 calculateFactorial
函数,并将 n
作为参数进行计算。根据函数的返回结果,我们在主函数中打印出相应的输出。
这道题考察了循环和条件判断的使用。通过使用循环和变量更新来计算给定整数的阶乘,我们可以得到阶乘的结果。同时,需要注意处理特殊情况,如输入的整数为负数时给出错误提示。
10.编写一个程序,接受用户输入的一个正整数n,计算并输出n的所有因数。
答案:
#include <stdio.h>
void calculateFactors(int n) {
printf("%d的因数有:", n);
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
printf("%d ", i);
}
}
printf("\n");
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
calculateFactors(n);
return 0;
}
解析:
这道题要求编写一个函数 calculateFactors
来计算给定正整数n的所有因数,并在主函数中调用该函数。在 calculateFactors
函数中,我们首先输出提示信息。然后,我们使用一个循环从1到n,判断每个数字是否是n的因数。如果是,就输出该数字。一个数n的因数是能整除n的正整数。最后,我们在输出完所有因数后换行。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 calculateFactors
函数,并将 n
作为参数进行计算和输出。
这道题考察了循环和条件判断的使用。通过使用循环和取模运算来计算给定正整数的所有因数,我们可以找到n的所有能够整除n的正整数。
11.编写一个程序,接受用户输入的一个正整数n,判断并输出n是否为素数。素数是只能被1和自身整除的正整数。
答案:
#include <stdio.h>
int isPrime(int n) {
if (n <= 1) {
return 0; // 不是素数
}
for (int i = 2; i <= n / 2; i++) {
if (n % i == 0) {
return 0; // 不是素数
}
}
return 1; // 是素数
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
if (isPrime(n)) {
printf("%d是素数\n", n);
} else {
printf("%d不是素数\n", n);
}
return 0;
}
解析:
这道题要求编写一个函数 isPrime
来判断给定正整数n是否为素数,并在主函数中调用该函数。在 isPrime
函数中,我们首先判断特殊情况,如果n小于等于1,则不是素数。然后,我们使用一个循环从2到n的一半,判断是否存在能够整除n的数。如果存在,说明n不是素数;否则,n是素数。在循环中,我们使用取模运算来判断是否能够整除,如果能够整除,则返回0表示不是素数。最后,如果循环结束都没有找到能整除n的数,则返回1表示是素数。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 isPrime
函数,并将 n
作为参数进行判断。根据函数的返回结果,我们在主函数中打印出相应的输出。
这道题考察了循环和条件判断的使用。通过使用循环和取模运算来判断给定正整数是否为素数,我们可以确定一个数是否只能被1和自身整除。
12.编写一个程序,接受用户输入的一个正整数n,计算并输出n的前n个斐波那契数。
答案:
#include <stdio.h>
void calculateFibonacciNumbers(int n) {
printf("前%d个斐波那契数:\n", n);
if (n >= 1) {
printf("0 ");
}
if (n >= 2) {
printf("1 ");
}
int a = 0;
int b = 1;
for (int i = 3; i <= n; i++) {
int c = a + b;
printf("%d ", c);
a = b;
b = c;
}
printf("\n");
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
calculateFibonacciNumbers(n);
return 0;
}
解析:
这道题要求编写一个函数 calculateFibonacciNumbers
来计算给定正整数n的前n个斐波那契数,并在主函数中调用该函数。在 calculateFibonacciNumbers
函数中,我们首先输出提示信息。然后,我们根据n的值来确定是否输出斐波那契数列的前两个数。接下来,我们使用变量 a
和 b
分别表示斐波那契数列的前两个数,初始化为0和1。使用一个循环从第三个数开始计算并输出剩余的斐波那契数列。在每次循环中,我们计算下一个数 c
,并将其输出。然后,我们更新 a
和 b
的值,将 b
赋值给 a
,将 c
赋值给 b
,以便下一次循环的计算。最后,在每行数字之间输出空格,并在斐波那契数列结束后换行。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 calculateFibonacciNumbers
函数,并将 n
作为参数进行计算和输出。
这道题考察了循环和变量更新的使用。通过使用循环和变量更新来计算给定正整数的前n个斐波那契数,我们可以生成指定数量的斐波那契数列。同时,根据n的值,我们决定是否输出斐波那契数列的前两个数。
13.编写一个程序,接受用户输入的一个正整数n,判断并输出n是否为回文数。回文数是指正序(从左向右)和倒序(从右向左)读都相同的数。
答案:
#include <stdio.h>
int isPalindrome(int n) {
int original = n;
int reversed = 0;
while (n > 0) {
int remainder = n % 10;
reversed = reversed * 10 + remainder;
n /= 10;
}
if (original == reversed) {
return 1; // 是回文数
} else {
return 0; // 不是回文数
}
}
int main() {
int n;
printf("请输入一个正整数:");
scanf("%d", &n);
if (isPalindrome(n)) {
printf("%d是回文数\n", n);
} else {
printf("%d不是回文数\n", n);
}
return 0;
}
解析:
这道题要求编写一个函数 isPalindrome
来判断给定正整数n是否为回文数,并在主函数中调用该函数。在 isPalindrome
函数中,我们首先保存原始的数值 n
,然后声明一个变量 reversed
并初始化为0,用于保存反转后的数值。接下来,我们使用一个循环将 n
反转,并将每一位上的数字加入到 reversed
中。在循环中,我们通过取模运算获取 n
的最后一位数字,并将其加入到 reversed
中,然后将 n
除以10去掉最后一位数字。最后,我们将反转后的数值 reversed
与原始数值 n
进行比较。如果它们相等,说明 n
是回文数;否则,不是回文数。在主函数中,我们声明一个整数变量 n
,用于接受用户输入的正整数。然后,我们调用 isPalindrome
函数,并将 n
作为参数进行判断。根据函数的返回结果,我们在主函数中打印出相应的输出。
这道题考察了循环、变量操作和条件判断的使用。通过将正整数反转,并与原始数值进行比较,我们可以判断一个数是否是回文数。
14.给定一个整数数组nums和一个目标值target,在数组中找出和为目标值的两个整数,并返回它们的索引。假设每个输入只对应一个答案,并且同一个元素不能使用两次。你可以按任意顺序返回答案。
#include <stdio.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
for (int i = 0; i < numsSize - 1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
int* result = (int*)malloc(2 * sizeof(int));
result[0] = i;
result[1] = j;
*returnSize = 2;
return result;
}
}
}
return NULL;
}
int main() {
int nums[] = {2, 7, 11, 15};
int target = 9;
int returnSize;
int* result = twoSum(nums, sizeof(nums) / sizeof(nums[0]), target, &returnSize);
if (result != NULL) {
printf("和为目标值的两个整数的索引是:%d和%d\n", result[0], result[1]);
free(result);
}
return 0;
}
解析:
这道题目给出了一个整数数组 nums
和一个目标值 target
,要求在数组中找到两个元素的和等于目标值,并返回它们的索引。首先,在 twoSum
函数中,我们使用两层循环遍历数组中的每对元素。对于每对元素 nums[i]
和 nums[j]
,我们判断它们的和是否等于目标值 target
。如果相等,我们创建一个大小为2的整数数组 result
,并将索引 i
和 j
存入其中,然后将 result
的地址返回,并通过指针 returnSize
返回数组的大小2。如果没有找到符合条件的元素对,则返回NULL。在主函数中,我们声明一个整数数组 nums
,并给出示例的初始值。然后,我们调用 twoSum
函数,传入数组、目标值以及一个指向 returnSize
变量的指针。根据函数的返回结果,我们判断是否找到符合条件的元素对,并打印它们的索引。需要注意的是,如果找到符合条件的元素对,我们需要手动释放动态分配的内存。
这道题目考察了数组和循环的使用。通过使用两层循环遍历数组中的元素对,我们可以找到和为目标值的两个元素,并返回它们的索引。
15.给定一个字符串s,编写一个函数将其反转并返回。例如,输入字符串 “hello”,反转后返回 “olleh”。
#include <stdio.h>
#include <string.h>
void reverseString(char* s) {
int length = strlen(s);
int left = 0;
int right = length - 1;
while (left < right) {
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
int main() {
char s[] = "hello";
printf("原字符串:%s\n", s);
reverseString(s);
printf("反转后的字符串:%s\n", s);
return 0;
}
解析:
这道题目给出了一个字符串 s
,要求编写一个函数 reverseString
将其反转,并返回反转后的字符串。在 reverseString
函数中,我们首先使用 strlen
函数获取字符串的长度,然后使用双指针的方法进行字符串反转。我们使用变量 left
和 right
分别表示字符串的左右指针,初始时分别指向字符串的第一个字符和最后一个字符。通过交换 left
和 right
指针所指向的字符,然后将 left
向右移动一位,将 right
向左移动一位,循环进行,直到 left
不再小于 right
。在主函数中,我们声明一个字符数组 s
,并给出示例的初始值。然后,我们调用 reverseString
函数进行字符串反转,并打印反转后的字符串。
这道题目考察了字符串的操作和双指针的应用。通过使用双指针技巧,我们可以在原字符串上进行字符交换,从而实现字符串的反转。
16.给定一个非空字符串s,编写一个函数,返回使字符串s中的字符按照出现频率降序排列的新字符串。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 定义字符出现频率的比较函数,用于排序
int compare(const void* a, const void* b) {
// 获取字符出现频率的差值
int freqDiff = ((const int*)b)[1] - ((const int*)a)[1];
// 如果频率相同,则按照字符的ASCII码升序排列
if (freqDiff == 0) {
return ((const int*)a)[0] - ((const int*)b)[0];
}
// 否则,按照频率的差值降序排列
return freqDiff;
}
char* frequencySort(char* s) {
int length = strlen(s);
int freq[128] = {0}; // 统计每个字符的出现频率
// 统计每个字符的出现频率
for (int i = 0; i < length; i++) {
freq[(int)s[i]]++;
}
// 创建一个二维数组,用于存储字符和对应的频率
int** freqArray = (int**)malloc(length * sizeof(int*));
for (int i = 0; i < length; i++) {
freqArray[i] = (int*)malloc(2 * sizeof(int));
freqArray[i][0] = (int)s[i]; // 存储字符的ASCII码
freqArray[i][1] = freq[(int)s[i]]; // 存储字符的出现频率
}
// 按照字符的出现频率降序排列
qsort(freqArray, length, sizeof(int*), compare);
// 根据排序结果生成新的字符串
char* result = (char*)malloc((length + 1) * sizeof(char));
int index = 0;
for (int i = 0; i < length; i++) {
for (int j = 0; j < freqArray[i][1]; j++) {
result[index++] = (char)freqArray[i][0];
}
}
result[length] = '\0';
// 释放动态分配的内存
for (int i = 0; i < length; i++) {
free(freqArray[i]);
}
free(freqArray);
return result;
}
int main() {
char s[] = "tree";
printf("原字符串:%s\n", s);
char* result = frequencySort(s);
printf("按照频率降序排列的新字符串:%s\n", result);
free(result);
return 0;
}
解析:
这道题目给出了一个非空字符串 s
,要求编写一个函数 frequencySort
,返回按照字符出现频率降序排列的新字符串。在函数中,我们首先使用数组 freq
统计每个字符的
出现频率,遍历字符串中的每个字符,通过 ASCII 码将其映射到 freq
数组中,并进行频率计数。然后,我们创建一个二维数组 freqArray
,用于存储字符和对应的频率,其中每个元素是一个大小为2的一维数组,分别存储字符的 ASCII 码和出现频率。接下来,我们使用 qsort
函数对 freqArray
进行排序,按照字符的出现频率降序排列,同时考虑字符的 ASCII 码升序排列作为辅助排序条件。然后,我们根据排序结果生成新的字符串 result
,通过遍历排序后的 freqArray
,将每个字符按照出现频率依次添加到 result
中。最后,我们在 result
字符串的末尾添加结束符 \0
,并释放动态分配的内存。在主函数中,我们声明一个字符数组 s
,并给出示例的初始值。然后,我们调用 frequencySort
函数进行字符频率排序,并打印结果。最后,记得释放动态分配的内存。
这道题目考察了字符串处理、数组操作和排序算法的应用。通过统计字符的出现频率,使用二维数组进行排序,并根据排序结果生成新的字符串,我们可以实现按照字符出现频率降序排列的功能。
17.给定一个整数数组nums,编写一个函数将数组中的所有0移动到数组的末尾,同时保持非零元素的相对顺序不变。例如,输入数组[0, 1, 0, 3, 12],移动后数组变为[1, 3, 12, 0, 0]。
#include <stdio.h>
void moveZeroes(int* nums, int numsSize) {
int insertPos = 0; // 插入位置
// 遍历数组,将非零元素前移
for (int i = 0; i < numsSize; i++) {
if (nums[i] != 0) {
nums[insertPos++] = nums[i];
}
}
// 将剩余位置补0
while (insertPos < numsSize) {
nums[insertPos++] = 0;
}
}
int main() {
int nums[] = {0, 1, 0, 3, 12};
int numsSize = sizeof(nums) / sizeof(nums[0]);
printf("原数组:");
for (int i = 0; i < numsSize; i++) {
printf("%d ", nums[i]);
}
printf("\n");
moveZeroes(nums, numsSize);
printf("移动后的数组:");
for (int i = 0; i < numsSize; i++) {
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}
解析:
这道题目给出了一个整数数组 nums
,要求编写一个函数 moveZeroes
将数组中的所有0移动到数组的末尾,同时保持非零元素的相对顺序不变。在函数中,我们使用一个变量 insertPos
来记录插入位置,初始时为0。我们遍历数组 nums
,当遇到非零元素时,将其前移至 insertPos
位置,并将 insertPos
自增1。这样,经过遍历后,所有非零元素都被移动到了数组的前面,且相对顺序保持不变。接着,我们使用一个循环将剩余位置补0,即将 insertPos
后的所有元素都设置为0。在主函数中,我们声明一个整数数组 nums
,并给出示例的初始值。然后,我们调用 moveZeroes
函数进行0的移动,并打印移动后的数组。
这道题目考察了数组的操作和元素的前移。通过遍历数组,将非零元素前移,然后将剩余位置补0,我们可以实现将数组中所有0移动到末尾的功能,并保持非零元素的相对顺序不变。
18.给定一个整数数组nums和一个整数目标值target,编写一个函数,在数组中找出两个数之和等于目标值,并返回它们的索引。假设每个输入只有一个答案,并且不可以重复利用相同的元素。例如,输入数组[2, 7, 11, 15],目标值为9,返回[0, 1]。
#include <stdio.h>
#include <stdlib.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
int* result = (int*)malloc(2 * sizeof(int)); // 存储结果的数组
// 使用双重循环遍历数组,寻找两个数之和等于目标值
for (int i = 0; i < numsSize - 1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
*returnSize = 2;
return result;
}
}
}
// 若未找到满足条件的结果,则返回空指针
*returnSize = 0;
return NULL;
}
int main() {
int nums[] = {2, 7, 11, 15};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int target = 9;
int returnSize;
printf("原数组:");
for (int i = 0; i < numsSize; i++) {
printf("%d ", nums[i]);
}
printf("\n");
int* result = twoSum(nums, numsSize, target, &returnSize);
if (returnSize == 2) {
printf("找到两个数之和等于目标值的索引:[%d, %d]\n", result[0], result[1]);
} else {
printf("未找到满足条件的结果。\n");
}
free(result);
return 0;
}
解析:
这道题目给出了一个整数数组 nums
、一个整数目标值 target
,要求编写一个函数 twoSum
在数组中找出两个数之和等于目标值,并返回它们的索引。在函数中,我们使用双重循环遍历数组 nums
,对于每对不同的元素,判断它们的和是否等于目标值 target
。如果找到满足条件的两个数,我们将它们的索引存储在动态分配的整数数组 result
中,并将结果数组的大小 returnSize
设置为2。然后,我们返回结果数组 result
。如果未找到满足条件的结果,则将 returnSize
设置为0,返回空指针。在主函数中,我们声明一个整数数组 nums
,并给出示例的初始值。然后
,我们调用 twoSum
函数查找满足条件的两个数的索引,并打印结果。最后,记得释放动态分配的内存。
这道题目考察了数组的操作和双重循环的应用。通过使用双重循环遍历数组,我们可以找到两个数之和等于目标值的索引,并返回结果。
19.给定一个链表,判断链表中是否有环。如果链表中存在环,则返回true;否则,返回false。
#include <stdio.h>
#include <stdbool.h>
// 链表结点的定义
struct ListNode {
int val;
struct ListNode* next;
};
bool hasCycle(struct ListNode* head) {
// 使用快慢指针判断链表是否有环
struct ListNode* slow = head; // 慢指针,每次移动一步
struct ListNode* fast = head; // 快指针,每次移动两步
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 如果快慢指针相遇,则链表有环
if (slow == fast) {
return true;
}
}
// 链表无环
return false;
}
int main() {
// 构建一个有环的链表作为示例
struct ListNode node1, node2, node3, node4;
node1.val = 1;
node2.val = 2;
node3.val = 3;
node4.val = 4;
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node2; // 将node4的next指针指向node2,形成环
bool result = hasCycle(&node1);
if (result) {
printf("链表中存在环。\n");
} else {
printf("链表中不存在环。\n");
}
return 0;
}
解析:
这道题目给出了一个链表,要求判断链表中是否有环。在函数 hasCycle
中,我们使用快慢指针来判断链表是否有环。快指针每次移动两步,而慢指针每次移动一步。如果链表中存在环,快指针最终会追上慢指针,两者相遇;如果链表中不存在环,快指针最终会到达链表的末尾,此时快慢指针不会相遇。因此,我们在循环中判断快慢指针是否相遇,如果相遇,则链表有环,返回true;如果快指针到达链表末尾,则链表无环,返回false。在主函数中,我们构建了一个有环的链表作为示例,然后调用 hasCycle
函数判断链表中是否存在环,并根据判断结果打印相应的信息。
这道题目考察了链表的操作和快慢指针的应用。通过使用快慢指针遍历链表,我们可以判断链表中是否有环,这是一种常见的判断链表是否有环的方法。
20.给定一个非负整数n,计算并返回n的阶乘。要求使用递归函数实现。
#include <stdio.h>
unsigned long long factorial(unsigned int n) {
// 递归结束条件:n为0或1时,直接返回1
if (n == 0 || n == 1) {
return 1;
}
// 递归计算 n 的阶乘:n! = n * (n-1)!
return n * factorial(n - 1);
}
int main() {
unsigned int n = 5;
unsigned long long result = factorial(n);
printf("%u的阶乘为:%llu\n", n, result);
return 0;
}
解析:
这道题目给定一个非负整数 n
,要求计算并返回 n
的阶乘。在函数 factorial
中,我们使用递归的方式实现阶乘的计算。递归的结束条件是 n
为0或1时,此时阶乘的结果为1,直接返回1。对于其他情况,我们使用递归计算 n
的阶乘,即 n! = n * (n-1)!
。在主函数中,我们给定一个非负整数 n
,调用 factorial
函数计算 n
的阶乘,并将结果打印出来。
这道题目考察了递归函数的应用。通过将阶乘的计算问题划分为更小规模的子问题,并利用递归函数不断求解子问题,最终得到整个问题的解。在实现递归函数时,我们需要考虑递归的结束条件和递归调用的方式,确保递归能够正确地终止并得到正确的结果。
21.给定一个整数数组 nums
,找出数组中两个数的最大异或值,并返回该值。
#include <stdio.h>
int findMaxXOR(int* nums, int numsSize) {
int maxXOR = 0; // 最大异或值
// 遍历数组中的每个元素
for (int i = 0; i < numsSize; i++) {
for (int j = i + 1; j < numsSize; j++) {
// 计算两个数的异或值
int currentXOR = nums[i] ^ nums[j];
// 更新最大异或值
if (currentXOR > maxXOR) {
maxXOR = currentXOR;
}
}
}
return maxXOR;
}
int main() {
int nums[] = {3, 10, 5, 25, 2, 8}; // 示例数组
int numsSize = sizeof(nums) / sizeof(nums[0]);
int result = findMaxXOR(nums, numsSize);
printf("数组中两个数的最大异或值为:%d\n", result);
return 0;
}
解析:
这道题目给定一个整数数组 nums
,要求找出数组中两个数的最大异或值,并返回该值。在函数 findMaxXOR
中,我们使用两重循环遍历数组中的每个元素,并计算当前两个数的异或值 currentXOR
。然后,我们与当前的最大异或值 maxXOR
进行比较,如果 currentXOR
大于 maxXOR
,则更新 maxXOR
的值。最终,返回最大异或值 maxXOR
。在主函数中,我们给出了一个示例数组 nums
,调用 findMaxXOR
函数计算数组中两个数的最大异或值,并打印结果。
这道题目考察了数组的操作和异或运算的应用。通过遍历数组中的每对元素,并计算它们的异或值,我们可以找到数组中两个数的最大异或值。异或运算具有特殊性质,能够在不使用额外空间的情况下计算两个数的异或值,且异或运算满足交换律和结合律。因此,通过遍历数组中的每对元素,我们能够找到最大的异或值。
22.给定一个整数数组 nums
,判断数组是否为单调递增或单调递减数组。如果数组是单调递增数组,则返回 1
;如果数组是单调递减数组,则返回 -1
;如果数组不满足单调性要求,则返回 0
。
#include <stdio.h>
int isMonotonic(int* nums, int numsSize) {
int increasing = 1; // 标记是否为递增数组
int decreasing = 1; // 标记是否为递减数组
// 遍历数组,判断递增和递减条件
for (int i = 1; i < numsSize; i++) {
if (nums[i] < nums[i - 1]) {
increasing = 0; // 不满足递增条件
}
if (nums[i] > nums[i - 1]) {
decreasing = 0; // 不满足递减条件
}
}
if (increasing) {
return 1; // 递增数组
} else if (decreasing) {
return -1; // 递减数组
} else {
return 0; // 既不是递增数组也不是递减数组
}
}
int main() {
int nums1[] = {1, 2, 3, 4, 5}; // 递增数组
int nums2[] = {5, 4, 3, 2, 1}; // 递减数组
int nums3[] = {1, 2, 3, 2, 4}; // 不满足单调性要求的数组
int result1 = isMonotonic(nums1, sizeof(nums1) / sizeof(nums1[0]));
int result2 = isMonotonic(nums2, sizeof(nums2) / sizeof(nums2[0]));
int result3 = isMonotonic(nums3, sizeof(nums3) / sizeof(nums3[0]));
printf("数组 nums1 是否为单调数组: %d\n", result1);
printf("数组 nums2 是否为单调数组: %d\n", result2);
printf("数组 nums3 是否为单调数组: %d\n", result3);
return 0;
}
解析:
这道题目给定一个整数数组 nums
,要求判断数组是否为单调递增或单调递减数组。在函数 isMonotonic
中,我们使用两个标记 increasing
和 decreasing
来记录是否满足递增和递减条件。通过遍历数组,对于相邻的元素进行比较,更新标记的值。如果存在某对相邻元素不满足递增条件,则将 increasing
标记置为 0
;如果存在某对相邻元素不满足递减条件,则将 decreasing
标记置为 0
。最终,根据标记的值返回相应的结果:如果 increasing
为 1
,则返回 1
表示递增数组;
如果 decreasing
为 1
,则返回 -1
表示递减数组;如果既不满足递增条件也不满足递减条件,则返回 0
表示不满足单调性要求。在主函数中,我们给出了三个示例数组,并调用 isMonotonic
函数判断数组是否为单调数组,并打印结果。
这道题目考察了数组的操作和条件判断。通过遍历数组,我们可以判断数组是否为单调递增或单调递减数组。在判断过程中,我们使用两个标记来记录是否满足递增和递减条件,并根据标记的值返回相应的结果。
23.给定一个字符串 s
,判断它是否是有效的括号序列。只包含字符 '('
,')'
,'['
,']'
,'{'
和 '}'
。要求使用栈的数据结构来实现。
#include <stdio.h>
#include <stdbool.h>
#define MAX_SIZE 100
typedef struct {
char stack[MAX_SIZE];
int top;
} Stack;
void initialize(Stack* s) {
s->top = -1;
}
bool isEmpty(Stack* s) {
return (s->top == -1);
}
bool isFull(Stack* s) {
return (s->top == MAX_SIZE - 1);
}
void push(Stack* s, char ch) {
if (isFull(s)) {
printf("栈已满,无法插入元素。\n");
return;
}
s->stack[++(s->top)] = ch;
}
char pop(Stack* s) {
if (isEmpty(s)) {
printf("栈已空,无法弹出元素。\n");
return '\0';
}
return s->stack[(s->top)--];
}
bool isValidParentheses(char* s) {
Stack stack;
initialize(&stack);
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
push(&stack, s[i]);
} else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
if (isEmpty(&stack)) {
return false; // 有右括号但栈为空,不匹配
}
char top = pop(&stack);
if ((s[i] == ')' && top != '(') || (s[i] == ']' && top != '[') || (s[i] == '}' && top != '{')) {
return false; // 括号不匹配
}
}
}
return isEmpty(&stack); // 栈为空表示所有括号都匹配
}
int main() {
char s1[] = "([])"; // 有效的括号序列
char s2[] = "([)]"; // 无效的括号序列
bool result1 = isValidParentheses(s1);
bool result2 = isValidParentheses(s2);
printf("字符串 s1 是否是有效的括号序列:%s\n", result1 ? "是" : "否");
printf("字符串 s2 是否是有效的括号序列:%s\n", result2 ? "是" : "否");
return 0;
}
解析:
这道题目给定一个字符串 s
,要求判断它是否是有效的括号序列。在函数 isValidParentheses
中,我们使用栈的数据结构来实现括号匹配的判断。首先,我们定义了一个结构体 Stack
,其中包含一个字符数组 stack
作为栈的存储空间,以及一个整数 top
作为栈顶指针。然后,我们实现了栈的基本操作函数:initialize
用于初始化栈,isEmpty
判断
栈是否为空,isFull
判断栈是否已满,push
将元素入栈,pop
将栈顶元素出栈。
在 isValidParentheses
函数中,我们遍历字符串 s
中的每个字符。对于左括号字符 '('
,'['
,'{'
,我们将其入栈。对于右括号字符 ')'
,']'
,'}'
,我们进行以下操作:
- 如果栈为空,则表示有右括号但栈为空,不匹配,直接返回
false
。 - 否则,从栈中弹出栈顶元素,并与当前的右括号字符进行匹配。如果匹配不成功,则表示括号不匹配,直接返回
false
。
遍历结束后,如果栈为空,表示所有括号都匹配,返回 true
,否则返回 false
。在主函数中,我们给出了两个示例字符串,并调用 isValidParentheses
函数判断字符串是否是有效的括号序列,并打印结果。
这道题目考察了栈的应用,特别是在括号匹配问题中的应用。通过使用栈来存储左括号,并在遇到右括号时进行匹配判断,我们可以判断一个字符串是否是有效的括号序列。栈的后进先出特性使得在括号匹配问题中具有较好的解决能力。
24.编写一个程序,实现插入排序算法对一个整数数组进行排序。要求在每次交换元素时打印出当前的数组元素序列。
#include <stdio.h>
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
void insertionSort(int arr[], int size) {
for (int i = 1; i < size; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
printf("当前数组序列:");
printArray(arr, size);
}
}
int main() {
int arr[] = {7, 2, 4, 1, 5, 3}; // 待排序的数组
int size = sizeof(arr) / sizeof(arr[0]);
printf("初始数组序列:");
printArray(arr, size);
printf("\n插入排序过程:\n");
insertionSort(arr, size);
printf("\n排序后的数组序列:");
printArray(arr, size);
return 0;
}
解析:
这道题目要求实现插入排序算法对一个整数数组进行排序,并在每次交换元素时打印出当前的数组元素序列。在函数 insertionSort
中,我们使用插入排序算法对数组进行排序。首先,我们从数组的第二个元素开始,将其作为待插入元素 key
。然后,我们将 key
与已排序的子数组进行比较,找到合适的位置将 key
插入。在插入的过程中,我们通过不断交换元素的方式实现元素的移动。每次交换元素后,我们打印当前的数组元素序列。
在主函数中,我们给出了一个示例数组 arr
,调用 insertionSort
函数对数组进行排序,并打印排序前和排序后的数组元素序列。
这道题目考察了插入排序算法的实现。插入排序是一种简单直观的排序算法,其核心思想是将数组分为已排序和未排序两部分,每次从未排序部分取一个元素并插入到已排序部分的适当位置。通过多次迭代和元素交换操作,最终实现整个数组的排序。在实现过程中,我们可以通过打印数组元素序列的方式来观察排序的过程和结果。
25.给定一个整数数组 nums
和一个整数目标值 target
,请编写一个函数 twoSum
,返回数组中两个元素的索引,使它们的和等于目标值。假设每个输入只有唯一解,并且同一个元素不能被重复使用。
#include <stdio.h>
#define MAX_SIZE 100
typedef struct {
int val;
int index;
} Element;
int compare(const void* a, const void* b) {
return ((Element*)a)->val - ((Element*)b)->val;
}
int* twoSum(int* nums, int size, int target) {
Element elements[MAX_SIZE];
for (int i = 0; i < size; i++) {
elements[i].val = nums[i];
elements[i].index = i;
}
qsort(elements, size, sizeof(Element), compare);
int left = 0;
int right = size - 1;
while (left < right) {
int sum = elements[left].val + elements[right].val;
if (sum == target) {
int* result = (int*)malloc(2 * sizeof(int));
result[0] = elements[left].index;
result[1] = elements[right].index;
return result;
} else if (sum < target) {
left++;
} else {
right--;
}
}
return NULL;
}
int main() {
int nums[] = {2, 7, 11, 15}; // 整数数组
int size = sizeof(nums) / sizeof(nums[0]);
int target = 9; // 目标值
int* result = twoSum(nums, size, target);
if (result != NULL) {
printf("两个元素的索引为:%d, %d\n", result[0], result[1]);
free(result);
} else {
printf("未找到满足条件的两个元素。\n");
}
return 0;
}
解析:
这道题目要求在给定的整数数组 nums
中找出两个元素的索引,使它们的和等于目标值 target
。在函数 twoSum
中,我们首先创建一个辅助数组 elements
,其中每个元素包含原始数组的值和索引。然后,对辅助数组进行排序,按照元素值的升序排列。接下来,我们使用双指针的方法来查找目标值。初始化左指针 left
指向数组的起始位置,右指针 right
指向数组的末尾位置。通过比较左右指针对应元素的和与目标值的大小,不断调整指针的位置,直到找到满足条件的两个元素或左右指针相遇。
在主函数中,我们给出了一个示例整数数组 nums
和目标值 target
,调用 twoSum
函数找到满足条件的两个元素的索引,并打印结果。
这道题目考察了数组的遍历和双指针的应用。通过将原始数组的元素和索引存储在辅助数组中,并对辅助数组进行排序,我们可以通过双指针的方法在有序数组中查找满足条件的两个元素。该题目的解法时间复杂度为 O(nlogn),其中 n 为数组的大小。
26.给定一个整数数组 nums
和一个目标整数 target
,请编写一个函数 threeSum
,在数组中找到所有不重复的三元组,使得三元组的元素之和等于目标值 target
。返回所有满足条件的三元组。
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int first; // 第一个元素
int second; // 第二个元素
int third; // 第三个元素
} Triplet;
int compare(const void* a, const void* b) {
return *(int*)a - *(int*)b;
}
Triplet* threeSum(int* nums, int size, int target, int* returnSize) {
// 创建结果数组
Triplet* result = (Triplet*)malloc(MAX_SIZE * sizeof(Triplet));
*returnSize = 0;
// 对数组进行排序
qsort(nums, size, sizeof(int), compare);
// 遍历数组
for (int i = 0; i < size - 2; i++) {
// 跳过重复的元素
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 使用双指针查找满足条件的三元组
int left = i + 1;
int right = size - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == target) {
// 找到满足条件的三元组,将其添加到结果数组中
result[*returnSize].first = nums[i];
result[*returnSize].second = nums[left];
result[*returnSize].third = nums[right];
(*returnSize)++;
// 跳过重复的元素
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
// 移动指针
left++;
right--;
} else if (sum < target) {
// 如果和小于目标值,移动左指针向右
left++;
} else {
// 如果和大于目标值,移动右指针向左
right--;
}
}
}
return result; // 返回结果数组
}
int main() {
int nums[] = { -1, 0, 1, 2, -1, -4 };
int size = sizeof(nums) / sizeof(nums[0]);
int target = 0;
int returnSize;
Triplet* result = threeSum(nums, size, target, &returnSize);
printf("满足条件的三元组:\n");
for (int i = 0; i < returnSize; i++) {
printf("%d %d %d\n", result[i].first, result[i].second, result[i].third);
}
return 0;
}
解析:
该问题可以通过双指针的方法来解决。首先,对数组进行排序,以便后续处理。然后,遍历数组,并使用双指针来找到满足条件的三元组。遍历过程中,固定一个元素 nums[i]
,并使用双指针 left
和 right
分别指向 nums[i]
后面的两端。根据当前三个元素的和与目标值进行比较,并根据比较结果移动指针。在找到满足条件的三元组时,将其添加到结果数组中,并跳过重复的元素。最后,返回结果数组。
27.给定一个整数数组 nums
和一个目标整数 target
,请编写一个函数 binarySearch
,实现在有序数组中查找目标元素,并返回其索引。如果目标元素不存在于数组中,返回 -1。
#include <stdio.h>
int binarySearch(int* nums, int size, int target) {
int left = 0; // 左边界索引
int right = size - 1; // 右边界索引
while (left <= right) {
int mid = left + (right - left) / 2; // 中间元素索引
if (nums[mid] == target) {
return mid; // 找到目标元素,返回索引
} else if (nums[mid] < target) {
left = mid + 1; // 目标元素在右半部分,更新左边界索引
} else {
right = mid - 1; // 目标元素在左半部分,更新右边界索引
}
}
return -1; // 目标元素不存在于数组中
}
int main() {
int nums[] = { 2, 4, 6, 8, 10, 12, 14 };
int size = sizeof(nums) / sizeof(nums[0]);
int target = 8;
int result = binarySearch(nums, size, target);
printf("目标元素在数组中的索引为: %d\n", result);
return 0;
}
解析:
该问题使用二分查找算法来在有序数组中查找目标元素。首先,初始化左边界索引 left
为 0,右边界索引 right
为数组大小减 1。然后,在循环中计算中间元素索引 mid
,并根据中间元素与目标元素的比较结果来更新边界索引。如果中间元素等于目标元素,则找到目标元素,返回其索引。如果中间元素小于目标元素,则目标元素在右半部分,更新左边界索引为 mid + 1
。如果中间元素大于目标元素,则目标元素在左半部分,更新右边界索引为 mid - 1
。在循环结束后,如果没有找到目标元素,则返回 -1。最后,输出目标元素在数组中的索引。
28.以下是按照您的要求生成的考研类型习题,包含问题、代码和解析,并在每句代码后添加了注释:
问题:
给定一个字符串 s
,请编写一个函数 reverseString
,将其反转并返回。
#include <stdio.h>
#include <string.h>
void reverseString(char* s) {
int left = 0; // 左边界索引
int right = strlen(s) - 1; // 右边界索引
while (left < right) {
char temp = s[left]; // 临时变量用于交换字符
s[left] = s[right];
s[right] = temp;
left++; // 更新左边界索引
right--; // 更新右边界索引
}
}
int main() {
char str[] = "Hello, World!";
printf("原始字符串:%s\n", str);
reverseString(str);
printf("反转后的字符串:%s\n", str);
return 0;
}
解析:
该问题使用双指针的方法来实现字符串反转。首先,初始化左边界索引 left
为 0,右边界索引 right
为字符串长度减 1。然后,进入循环,交换左右边界对应的字符,并同时更新左边界索引和右边界索引。在循环结束后,字符串的字符顺序被反转。最后,输出反转后的字符串。
29.给定一个整数数组 nums
和一个目标整数 target
,请编写一个函数 findTwoSum
,找到数组中两个元素的和等于目标值 target
的索引,并返回这两个索引。
#include <stdio.h>
void findTwoSum(int* nums, int size, int target, int* index1, int* index2) {
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (nums[i] + nums[j] == target) {
*index1 = i;
*index2 = j;
return;
}
}
}
}
int main() {
int nums[] = { 2, 7, 11, 15 };
int size = sizeof(nums) / sizeof(nums[0]);
int target = 9;
int index1, index2;
findTwoSum(nums, size, target, &index1, &index2);
printf("索引1:%d\n", index1);
printf("索引2:%d\n", index2);
return 0;
}
解析:
该问题使用暴力搜索的方法来寻找数组中两个元素的和等于目标值 target
的索引。使用两层循环遍历数组,对每一对不同的元素进行求和,并与目标值比较。如果找到了满足条件的两个元素,记录它们的索引并返回。在主函数中,声明两个变量 index1
和 index2
用于存储找到的索引。最后,输出这两个索引。
30.给定一个字符串 s
,请编写一个函数 countVowels
,统计字符串中元音字母的个数,并返回结果。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int countVowels(char* s) {
int count = 0; // 元音字母计数器
for (int i = 0; i < strlen(s); i++) {
char ch = tolower(s[i]); // 将字符转换为小写形式
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
count++; // 遇到元音字母,计数器加一
}
}
return count; // 返回元音字母个数
}
int main() {
char str[] = "Hello, World!";
int vowelsCount = countVowels(str);
printf("元音字母个数:%d\n", vowelsCount);
return 0;
}
解析:
该问题使用循环遍历字符串的每个字符,并通过 tolower
函数将字符转换为小写形式,然后与元音字母进行比较。如果字符是元音字母之一(a、e、i、o、u),则计数器加一。最后,返回元音字母的个数。在主函数中,将字符串传递给 countVowels
函数,并输出计算得到的元音字母个数。
31.给定一个整数数组 nums
,请编写一个函数 findMax
,找到数组中的最大元素,并返回其值。
#include <stdio.h>
int findMax(int* nums, int size) {
int max = nums[0]; // 假设数组的第一个元素为最大值
for (int i = 1; i < size; i++) {
if (nums[i] > max) {
max = nums[i]; // 找到更大的元素,更新最大值
}
}
return max; // 返回最大值
}
int main() {
int nums[] = { 10, 5, 8, 3, 15, 12 };
int size = sizeof(nums) / sizeof(nums[0]);
int max = findMax(nums, size);
printf("最大元素:%d\n", max);
return 0;
}
解析:
该问题使用循环遍历数组中的每个元素,并通过比较找到数组中的最大元素。假设数组的第一个元素为最大值,然后依次与后面的元素进行比较,如果找到更大的元素,则更新最大值。最后,返回最大值。在主函数中,声明变量 max
来存储最大元素,并输出该值。
32.给定一个整数数组 nums
和一个目标整数 target
,请编写一个函数 findTargetSum
,判断数组中是否存在两个元素的和等于目标值 target
。
#include <stdio.h>
int findTargetSum(int* nums, int size, int target) {
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (nums[i] + nums[j] == target) {
return 1; // 找到满足条件的两个元素,返回 1
}
}
}
return 0; // 未找到满足条件的两个元素,返回 0
}
int main() {
int nums[] = { 2, 4, 6, 8, 10 };
int size = sizeof(nums) / sizeof(nums[0]);
int target = 14;
int result = findTargetSum(nums, size, target);
if (result) {
printf("存在两个元素的和等于目标值。\n");
} else {
printf("不存在两个元素的和等于目标值。\n");
}
return 0;
}
解析:
该问题使用两层循环遍历数组中的所有元素对,并计算它们的和与目标值进行比较。如果找到满足条件的两个元素,即它们的和等于目标值,则返回 1。如果循环结束后仍未找到满足条件的两个元素,则返回 0。在主函数中,将数组、数组大小和目标值传递给 findTargetSum
函数,并根据返回值输出相应的结果。如果返回值为 1,则存在两个元素的和等于目标值;如果返回值为 0,则不存在。
33.给定一个整数数组 nums
和一个目标整数 target
,请编写一个函数 findTwoSum
,找到数组中两个元素的和等于目标值 target
的索引,并返回这两个索引。
#include <stdio.h>
void findTwoSum(int* nums, int size, int target, int* index1, int* index2) {
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (nums[i] + nums[j] == target) {
*index1 = i; // 将找到的索引赋值给 index1
*index2 = j; // 将找到的索引赋值给 index2
return;
}
}
}
}
int main() {
int nums[] = { 2, 7, 11, 15 };
int size = sizeof(nums) / sizeof(nums[0]);
int target = 9;
int index1, index2;
findTwoSum(nums, size, target, &index1, &index2);
printf("索引1:%d\n", index1);
printf("索引2:%d\n", index2);
return 0;
}
解析:
该问题使用两层循环遍历数组中的每一对不同的元素,并计算它们的和与目标值进行比较。如果找到满足条件的两个元素,将它们的索引赋值给 index1
和 index2
,然后返回。在主函数中,声明两个变量 index1
和 index2
,用于存储找到的索引。将数组、数组大小和目标值传递给 findTwoSum
函数,并通过地址传递的方式获取计算结果。最后,输出这两个索引。
34.给定一个字符串 s
,请编写一个函数 reverseString
,将字符串中的字符顺序反转,并返回结果。
#include <stdio.h>
#include <string.h>
void reverseString(char* s) {
int length = strlen(s);
int left = 0;
int right = length - 1;
while (left < right) {
// 交换左右两个字符
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
int main() {
char str[] = "Hello, World!";
printf("原始字符串:%s\n", str);
reverseString(str);
printf("反转字符串:%s\n", str);
return 0;
}
解析:
该问题使用双指针方法,定义两个指针 left
和 right
分别指向字符串的首尾字符。通过交换左右指针所指向的字符,实现字符顺序的反转。循环进行交换操作,直到左指针超过右指针,即完成字符串反转。在主函数中,声明一个字符串 str
,并输出原始字符串。然后调用 reverseString
函数对字符串进行反转,并输出反转后的结果。
35.给定一个整数数组 nums
,请编写一个函数 removeDuplicates
,将数组中重复的元素去除,并返回去重后的数组长度。
#include <stdio.h>
int removeDuplicates(int* nums, int size) {
if (size == 0) {
return 0; // 数组为空,直接返回长度 0
}
int index = 0; // 去重后的数组索引
for (int i = 1; i < size; i++) {
if (nums[i] != nums[index]) {
index++; // 不重复的元素,更新索引
nums[index] = nums[i]; // 将不重复的元素存入新的位置
}
}
return index + 1; // 返回去重后的数组长度
}
int main() {
int nums[] = { 1, 1, 2, 2, 3, 3, 3, 4, 5 };
int size = sizeof(nums) / sizeof(nums[0]);
int length = removeDuplicates(nums, size);
printf("去重后的数组长度:%d\n", length);
printf("去重后的数组:");
for (int i = 0; i < length; i++) {
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}
解析:
该问题使用双指针方法,定义一个索引变量 index
,用于表示去重后的数组的索引位置。遍历数组,当当前元素与前一个元素不相等时,将当前元素存储在 index+1
的位置,并更新 index
的值。这样就能保证去重后的数组中只包含不重复的元素。最后,返回 index+1
作为去重后的数组长度。在主函数中,声明一个整数数组 nums
,并调用 removeDuplicates
函数进行去重操作。输出去重后的数组长度和去重后的数组内容。
36.给定一个链表的头节点 head
,请编写一个函数 reverseList
,将链表反转,并返回反转后的链表的头节点。
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* prev = NULL;
struct ListNode* curr = head;
while (curr != NULL) {
struct ListNode* nextTemp = curr->next; // 保存当前节点的下一个节点
curr->next = prev; // 当前节点指向前一个节点,完成反转
prev = curr; // 更新前一个节点为当前节点
curr = nextTemp; // 更新当前节点为下一个节点
}
return prev; // 返回反转后的链表头节点
}
struct ListNode* createNode(int val) {
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = val;
newNode->next = NULL;
return newNode;
}
void printList(struct ListNode* head) {
struct ListNode* curr = head;
while (curr != NULL) {
printf("%d ", curr->val);
curr = curr->next;
}
printf("\n");
}
int main() {
struct ListNode* head = createNode(1);
struct ListNode* second = createNode(2);
struct ListNode* third = createNode(3);
struct ListNode* fourth = createNode(4);
struct ListNode* fifth = createNode(5);
head->next = second;
second->next = third;
third->next = fourth;
fourth->next = fifth;
printf("原始链表:");
printList(head);
struct ListNode* reversedHead = reverseList(head);
printf("反转链表:");
printList(reversedHead);
return 0;
}
解析:
该问题使用迭代方法进行链表反转。定义两个指针 prev
和 curr
,分别指向前一个节点和当前节点,初始时 prev
为 NULL,curr
指向链表的头节点 head
。在循环中,通过临时变量保存当前节点的下一个节点,然后将当前节点指向前一个节点,完成反转操作。接着更新 prev
为当前节点,curr
为下一个节点,继续迭代。当 curr
为 NULL,即遍历到链表尾部时,循环结束。最后返回 prev
,即为反转后的链表的头节点。在主函数中,创建了一个包含 5 个节点的链表,并调用 reverseList
函数进行链表反转。输出原始链表和反转后的链表的值。
37.给定一个二叉树的根节点 root
,请编写一个函数 inorderTraversal
,实现二叉树的中序遍历,并返回遍历结果。
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
};
struct TreeNode* createNode(int val) {
struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
newNode->val = val;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
void inorderTraversalHelper(struct TreeNode* root, int* result, int* index) {
if (root == NULL) {
return;
}
inorderTraversalHelper(root->left, result, index); // 中序遍历左子树
result[(*index)++] = root->val; // 访问当前节点
inorderTraversalHelper(root->right, result, index); // 中序遍历右子树
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int nodeCount = 0; // 统计二叉树节点数
int* result;
// 计算二叉树节点数
void countNodes(struct TreeNode* node) {
if (node == NULL) {
return;
}
countNodes(node->left);
nodeCount++;
countNodes(node->right);
}
countNodes(root);
*returnSize = nodeCount; // 设置返回结果的大小
result = (int*)malloc(nodeCount * sizeof(int)); // 分配内存空间
int index = 0; // 结果数组的索引
inorderTraversalHelper(root, result, &index); // 中序遍历二叉树
return result;
}
int main() {
struct TreeNode* root = createNode(1);
struct TreeNode* node2 = createNode(2);
struct TreeNode* node3 = createNode(3);
struct TreeNode* node4 = createNode(4);
struct TreeNode* node5 = createNode(5);
root->left = node2;
root->right = node3;
node2->left = node4;
node2->right = node5;
int size;
int* result = inorderTraversal(root, &size);
printf("中序遍历结果:");
for (int i = 0; i < size; i++) {
printf("%d ", result[i]);
}
printf("\n");
free(result);
return 0;
}
解析:
该问题使用递归方法实现二叉树的中序遍历。定义一个辅助函数 inorderTraversalHelper
,它接受当前节点 root
、存储遍历结果的数组 result
和结果数组的索引 index
。在辅助函数中,先递归遍历左子树,然后将当前节点的值存入结果数组,并递归遍历右子树。在主函数 inorderTraversal
中,首先统计二叉树的节点数,然后分配结果数组的内存空间。接着调用辅助函数 inorderTraversalHelper
进行中序遍历,将结果存入结果数组。最后返回结果数组和结果数组的大小。在主函数中,创建了一个二叉树,并调用 inorderTraversal
函数进行中序遍历。输出遍历结果。
38.给定一个字符串 s
,请编写一个函数 isValid
,判断该字符串中的括号是否匹配。
#include <stdio.h>
#include <stdbool.h>
#define MAX_STACK_SIZE 100
typedef struct {
char data[MAX_STACK_SIZE];
int top;
} Stack;
void initializeStack(Stack* stack) {
stack->top = -1;
}
bool isStackEmpty(Stack* stack) {
return (stack->top == -1);
}
bool isStackFull(Stack* stack) {
return (stack->top == MAX_STACK_SIZE - 1);
}
void push(Stack* stack, char element) {
if (isStackFull(stack)) {
printf("Error: Stack is full.\n");
return;
}
stack->data[++stack->top] = element;
}
char pop(Stack* stack) {
if (isStackEmpty(stack)) {
printf("Error: Stack is empty.\n");
return '\0';
}
return stack->data[stack->top--];
}
bool isValid(char* s) {
Stack stack;
initializeStack(&stack);
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
push(&stack, s[i]); // 遇到左括号入栈
} else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
if (isStackEmpty(&stack)) {
return false; // 栈为空,无法匹配右括号
}
char top = pop(&stack); // 弹出栈顶元素
if ((s[i] == ')' && top != '(') ||
(s[i] == ']' && top != '[') ||
(s[i] == '}' && top != '{')) {
return false; // 右括号与栈顶元素不匹配
}
}
}
return isStackEmpty(&stack); // 字符串遍历完毕后,栈为空则匹配成功
}
int main() {
char* s1 = "(([]))";
char* s2 = "{[()]}";
char* s3 = "({[)}]";
char* s4 = "([]}";
printf("字符串 %s 括号是否匹配:%s\n", s1, isValid(s1) ? "Yes" : "No");
printf("字符串 %s 括号是否匹配:%s\n", s2, isValid(s2) ? "Yes" : "No");
printf("字符串 %s 括号是否匹配:%s\n", s3, isValid(s3) ? "Yes" : "No");
printf("字符串 %s 括号是否匹配:%s\n", s4, isValid(s4) ? "Yes" : "No");
return 0;
}
解析:
该问题使用栈来判断括号的匹配情况。定义了一个栈的结构体,并实现了栈的基本操作函数。在函数 isValid
中,首先初始化一个栈,然后遍历字符串中的每个字符。如果遇到左括号,则将其入栈;如果遇到右括号,则与栈顶元素进行匹配。若栈为空,无法匹配右括号,返回 false;若右括号与栈顶元素不匹配,返回 false。遍历完成后,检查栈是否为空,若为空则说明所有括号都匹配成功,返回 true,否则返回 false。在主函数中,测试了不同的字符串,并输出括号的匹配结果。
39.给定一个有序整数数组 nums
和一个目标值 target
,请编写一个函数 search
,在数组中查找目标值,并返回其索引。如果目标值不存在于数组中,返回 -1。
#include <stdio.h>
int search(int* nums, int numsSize, int target) {
int left = 0; // 左边界
int right = numsSize - 1; // 右边界
while (left <= right) {
int mid = left + (right - left) / 2; // 中间元素的索引
if (nums[mid] == target) {
return mid; // 找到目标值,返回索引
} else if (nums[mid] < target) {
left = mid + 1; // 目标值在右半部分,更新左边界
} else {
right = mid - 1; // 目标值在左半部分,更新右边界
}
}
return -1; // 目标值不存在于数组中,返回 -1
}
int main() {
int nums[] = {2, 5, 8, 12, 16, 23, 38, 42, 55, 67};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int target1 = 16;
int target2 = 25;
int result1 = search(nums, numsSize, target1);
int result2 = search(nums, numsSize, target2);
printf("目标值 %d 的索引: %d\n", target1, result1);
printf("目标值 %d 的索引: %d\n", target2, result2);
return 0;
}
解析:
该问题使用二分查找算法在有序数组中查找目标值。定义了左边界 left
和右边界 right
分别初始化为数组的起始索引和结束索引。在每一轮循环中,计算中间元素的索引 mid
,并与目标值进行比较。如果中间元素等于目标值,则找到了目标值,返回其索引。如果中间元素小于目标值,则目标值在右半部分,更新左边界为 mid + 1
。如果中间元素大于目标值,则目标值在左半部分,更新右边界为 mid - 1
。通过不断缩小搜索范围,最终可以找到目标值或确定其不存在于数组中。在主函数中,测试了不同的目标值,并输出其在数组中的索引。
40.以下是按照您的要求生成的考研类型习题,包含问题、代码和解析,并在每句代码后添加了注释:
问题:
给定一个整数数组 nums
,请编写一个函数 maxSubArray
,计算数组中连续子数组的最大和,并返回该最大和。
#include <stdio.h>
int maxSubArray(int* nums, int numsSize) {
int maxSum = nums[0]; // 最大和的初始值为第一个元素
int currentSum = nums[0]; // 当前和的初始值为第一个元素
for (int i = 1; i < numsSize; i++) {
if (currentSum < 0) {
currentSum = nums[i]; // 如果当前和小于零,舍弃前面的子数组
} else {
currentSum += nums[i]; // 如果当前和大于等于零,累加当前元素
}
if (currentSum > maxSum) {
maxSum = currentSum; // 更新最大和
}
}
return maxSum;
}
int main() {
int nums[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int maxSum = maxSubArray(nums, numsSize);
printf("连续子数组的最大和为:%d\n", maxSum);
return 0;
}
解析:
该问题使用动态规划的思想来计算数组中连续子数组的最大和。定义了两个变量 maxSum
和 currentSum
,分别表示最大和和当前和。首先将 maxSum
和 currentSum
初始化为数组的第一个元素。然后从数组的第二个元素开始遍历,判断当前和 currentSum
是否小于零,如果小于零,则舍弃前面的子数组,将当前元素作为新的起点;如果大于等于零,则将当前元素累加到当前和 currentSum
中。在每次累加后,判断当前和 currentSum
是否大于最大和 maxSum
,如果是,则更新最大和。通过遍历整个数组,最终可以得到连续子数组的最大和。在主函数中,测试了给定数组,并输出连续子数组的最大和。
41.给定一个整数数组 nums
,请编写一个函数 removeDuplicates
,将数组中重复的元素去除,并返回去重后的数组的长度。假设原数组已经按照非递减顺序排序。
#include <stdio.h>
int removeDuplicates(int* nums, int numsSize) {
if (numsSize == 0) {
return 0; // 空数组,返回长度为 0
}
int uniqueIndex = 0; // 唯一元素的索引
for (int i = 1; i < numsSize; i++) {
if (nums[i] != nums[uniqueIndex]) {
uniqueIndex++; // 发现新的唯一元素,更新唯一元素的索引
nums[uniqueIndex] = nums[i]; // 将唯一元素放置在正确的位置上
}
}
return uniqueIndex + 1; // 唯一元素的个数即为去重后的数组的长度
}
int main() {
int nums[] = {1, 1, 2, 2, 2, 3, 4, 4, 5};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int length = removeDuplicates(nums, numsSize);
printf("去重后的数组长度为:%d\n", length);
printf("去重后的数组为:");
for (int i = 0; i < length; i++) {
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}
解析:
该问题要求对已排序的整数数组进行去重操作,并返回去重后的数组的长度。使用双指针的方法来解决该问题。首先判断数组是否为空,若为空,则直接返回长度为 0。定义一个变量 uniqueIndex
来记录当前唯一元素的索引,初始值为 0。从数组的第二个元素开始遍历,如果当前元素与唯一元素不相等,则说明发现了一个新的唯一元素,将其放置在唯一元素的下一个位置,并更新 uniqueIndex
的值。通过遍历整个数组,即可完成去重操作。最后返回 uniqueIndex + 1
,即去重后的数组的长度。在主函数中,测试了给定数组,并输出去重后的数组的长度和去重后的数组。
42.给定一个字符串 str
,请编写一个函数 reverseString
,将字符串中的字符逆序排列,并返回逆序后的字符串。
#include <stdio.h>
#include <string.h>
void reverseString(char* str) {
int left = 0; // 左指针,指向字符串起始位置
int right = strlen(str) - 1; // 右指针,指向字符串结束位置
while (left < right) {
char temp = str[left]; // 交换左右指针所指向的字符
str[left] = str[right];
str[right] = temp;
left++; // 左指针右移
right--; // 右指针左移
}
}
int main() {
char str[] = "Hello, World!";
printf("原始字符串:%s\n", str);
reverseString(str);
printf("逆序后的字符串:%s\n", str);
return 0;
}
解析:
该问题要求对给定的字符串进行逆序排列。使用双指针的方法来解决该问题。首先定义一个左指针 left
,指向字符串的起始位置,以及一个右指针 right
,指向字符串的结束位置。通过循环遍历字符串,将左指针所指向的字符与右指针所指向的字符进行交换,然后将左指针右移,右指针左移,继续进行下一轮的交换操作,直到左指针大于等于右指针为止。最终可以将字符串中的字符逆序排列。在主函数中,测试了给定字符串,并输出逆序后的字符串。
43.给定一个正整数 num
,请编写一个函数 isPerfectSquare
,判断该数是否为完全平方数。
#include <stdio.h>
int isPerfectSquare(int num) {
if (num < 0) {
return 0; // 负数不是完全平方数
}
if (num <= 1) {
return 1; // 0和1是完全平方数
}
int left = 1; // 左边界
int right = num; // 右边界
while (left <= right) {
long long mid = left + (right - left) / 2; // 使用二分查找,将中间值设置为 long long 类型以防止溢出
if (mid * mid == num) {
return 1; // 找到完全平方数
} else if (mid * mid < num) {
left = mid + 1; // 在右半部分继续查找
} else {
right = mid - 1; // 在左半部分继续查找
}
}
return 0; // 没有找到完全平方数
}
int main() {
int num = 16;
if (isPerfectSquare(num)) {
printf("%d 是完全平方数\n", num);
} else {
printf("%d 不是完全平方数\n", num);
}
return 0;
}
解析:
该问题要求判断给定的正整数是否为完全平方数。使用二分查找的方法来解决该问题。首先判断特殊情况,若给定的数小于0,则直接返回 0,因为负数不是完全平方数;若给定的数为0或1,则直接返回 1,因为0和1是完全平方数。对于其他正整数,使用二分查找来找到其平方根。定义左边界 left
为1,右边界 right
为给定数本身。通过循环进行二分查找,每次取中间值 mid
,判断 mid * mid
是否等于给定数,如果是,则说明找到了完全平方数,返回 1;如果 mid * mid
小于给定数,说明完全平方数在右半部分,更新左边界为 mid + 1
;如果 mid * mid
大于给定数,说明完全平方数在左半部分,更新右边界为 mid - 1
。最终,如果循环结束仍未找到完全平方数,则返回 0。在主函数中,测试了给定数,并输出判断结果。
44.给定一个整数数组 nums
和一个目标值 target
,请编写一个函数 twoSum
,找出数组中和为目标值的两个元素的索引,并返回这两个索引值。
#include <stdio.h>
int* twoSum(int* nums, int numsSize, int target) {
static int result[2]; // 存储结果的数组
for (int i = 0; i < numsSize - 1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
return result; // 找到目标值,返回结果
}
}
}
return NULL; // 没有找到目标值,返回空指针
}
int main() {
int nums[] = {2, 7, 11, 15};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int target = 9;
int* indices = twoSum(nums, numsSize, target);
if (indices != NULL) {
printf("和为目标值的两个元素的索引为:%d, %d\n", indices[0], indices[1]);
} else {
printf("没有找到和为目标值的两个元素\n");
}
return 0;
}
解析:
该问题要求在给定的整数数组中找到和为目标值的两个元素,并返回这两个元素的索引。使用两层循环的暴力解法来解决该问题。外层循环遍历数组中的每个元素 nums[i]
,内层循环从外层循环的下一个元素开始遍历,找到与 nums[i]
相加等于目标值 target
的元素 nums[j]
,将其索引存储在 result
数组中,并返回结果。如果在两层循环结束后仍未找到满足条件的两个元素,则返回空指针。在主函数中,测试了给定数组和目标值,并输出满足条件的两个元素的索引。
45.给定一个正整数n,编写一个递归函数printNumbers
,按顺序打印从1到n的所有数字。
要求:
- 不能使用循环或迭代器,只能使用递归实现。
- 考虑输入的边界情况,当n为负数时,不输出任何数字。
#include <stdio.h>
void printNumbers(int n) {
if (n <= 0) {
return; // 当n为负数或0时,直接返回
}
printNumbers(n - 1); // 递归调用,打印从1到n-1的数字
printf("%d ", n); // 打印当前数字n
}
int main() {
int n = 5;
printf("从1到%d的数字为:", n);
printNumbers(n);
printf("\n");
return 0;
}
解析:
该问题要求按顺序打印从1到给定正整数n的所有数字,使用递归方式实现。在递归函数printNumbers
中,首先判断n的值是否小于等于0,若是则直接返回,表示递归终止条件。否则,递归调用printNumbers(n - 1)
,打印从1到n-1的所有数字。然后在递归调用之后,打印当前数字n。这样就能够按照从1到n的顺序递归地打印所有数字。在主函数中,测试了给定的正整数n,并输出从1到n的所有数字。
通过递归的方式,每次递归都将问题的规模减小,直到达到递归终止条件。递归函数中的代码在每次递归调用前后执行,实现了按顺序打印数字的效果。
46.给定一个字符串s
和一个字符c
,编写一个函数countOccurrences
,统计字符串s
中字符c
的出现次数,并返回结果。
要求:
- 字符串
s
不为空,且长度不超过1000。 - 字符
c
可以是任意ASCII字符。
#include <stdio.h>
int countOccurrences(const char* s, char c) {
if (s == NULL || *s == '\0') {
return 0; // 若字符串为空或已到达字符串结尾,则返回0
}
if (*s == c) {
return 1 + countOccurrences(s + 1, c); // 若当前字符与目标字符相同,则返回1,并递归统计后续子串中的出现次数
} else {
return countOccurrences(s + 1, c); // 若当前字符与目标字符不同,则递归统计后续子串中的出现次数
}
}
int main() {
char s[] = "Hello, World!";
char c = 'o';
int occurrences = countOccurrences(s, c);
printf("字符 '%c' 在字符串 '%s' 中出现的次数为:%d\n", c, s, occurrences);
return 0;
}
解析:
该问题要求统计字符串s
中字符c
的出现次数,使用递归方式实现。在递归函数countOccurrences
中,首先判断字符串s
是否为空或已到达字符串结尾,若是,则返回0,表示递归终止条件。然后判断当前字符是否与目标字符c
相同,若是,则返回1加上递归调用countOccurrences(s + 1, c)
,表示当前字符的出现次数加上后续子串中目标字符的出现次数。若当前字符与目标字符不同,则直接递归调用countOccurrences(s + 1, c)
,统计后续子串中目标字符的出现次数。通过递归的方式,逐个字符地判断并统计出现次数,最终返回结果。在主函数中,测试了给定的字符串s
和字符c
,并输出字符c
在字符串s
中的出现次数。
递归函数在每次递归调用时,通过移动字符串指针s
的位置,来实现逐个字符的判断和统计。通过不断缩小问题的规模,直到达到递归终止条件,最终得到结果。
47.给定一个整数数组 nums
,编写一个函数 findMaxConsecutiveOnes
,统计数组中最长连续的1的个数,并返回结果。
要求:
- 数组
nums
不为空,且长度不超过 10^4。 - 数组
nums
中只包含 0 和 1 两种元素。
#include <stdio.h>
int findMaxConsecutiveOnes(int* nums, int numsSize) {
int maxCount = 0; // 最长连续1的个数
int currentCount = 0; // 当前连续1的个数
for (int i = 0; i < numsSize; i++) {
if (nums[i] == 1) {
currentCount++; // 遇到1,当前连续1的个数加1
} else {
if (currentCount > maxCount) {
maxCount = currentCount; // 遇到0,更新最长连续1的个数
}
currentCount = 0; // 当前连续1的个数清零
}
}
if (currentCount > maxCount) {
maxCount = currentCount; // 处理数组末尾的情况
}
return maxCount;
}
int main() {
int nums[] = {1, 1, 0, 1, 1, 1, 0, 1, 1};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int maxConsecutiveOnes = findMaxConsecutiveOnes(nums, numsSize);
printf("最长连续的1的个数为:%d\n", maxConsecutiveOnes);
return 0;
}
解析:
该问题要求统计整数数组 nums
中最长连续的1的个数,使用迭代方式实现。在迭代过程中,定义两个变量 maxCount
和 currentCount
,分别表示最长连续1的个数和当前连续1的个数。遍历数组 nums
,当遇到元素为1时,当前连续1的个数加1;当遇到元素为0时,判断当前连续1的个数是否大于最长连续1的个数,若是,则更新最长连续1的个数为当前连续1的个数,并将当前连续1的个数清零。遍历结束后,若当前连续1的个数仍大于最长连续1的个数,则更新最长连续1的个数为当前连续1的个数。最后返回最长连续1的个数。在主函数中,测试了给定的整数数组 nums
,并输出最长连续的1的个数。
通过迭代的方式遍历数组,根据元素的值来更新计数器,从而统计最长连续1的个数。迭代过程中只需要常数级的额外空间,具有较高的效率。
48.给定一个正整数数组 nums
和一个目标值 target
,编写一个函数 twoSum
,找到数组中两个数的下标,使得它们的和等于目标值,并返回这两个下标。
要求:
- 假设每个输入只对应唯一的答案。
- 数组
nums
中至少存在两个数。 - 返回的下标要求按照从小到大的顺序排列。
#include <stdio.h>
#include <stdlib.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
int* result = (int*)malloc(2 * sizeof(int)); // 分配存放结果的内存空间
*returnSize = 2; // 返回结果的大小
for (int i = 0; i < numsSize - 1; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
result[0] = i; // 找到两个数的下标
result[1] = j;
return result;
}
}
}
return result; // 若没有找到满足条件的下标,则返回默认结果
}
int main() {
int nums[] = {2, 7, 11, 15};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int target = 9;
int returnSize;
int* indices = twoSum(nums, numsSize, target, &returnSize);
printf("数组中和为目标值 %d 的两个数的下标为:%d, %d\n", target, indices[0], indices[1]);
free(indices); // 释放动态分配的内存空间
return 0;
}
解析:
该问题要求在给定的正整数数组 nums
中找到两个数的下标,使得它们的和等于目标值 target
,并返回这两个下标。使用双重循环遍历数组,通过判断两个数的和是否等于目标值,找到满足条件的下标。在主函数中,定义了一个整型指针 result
,用于存放结果的下标,并动态分配了2个整型空间给指针 result
,用于存放两个下标。在双重循环中,若找到满足条件的两个数,则将下标保存到 result
中并返回。若遍历完整个数组仍未找到满足条件的下标,则返回默认结果。最后,在主函数中输出满足条件的两个数的下标。注意,动态分配的内存空间需要在使用完毕后进行释放。
该问题的解法是暴力搜索法,时间复杂度较高,为 O(n^2),其中 n 为数组的长度。在面对较大规模的输入时,效率较低,可以考虑其他更优化的算法。
49.给定一个字符串 s
,编写一个函数 reverseString
,将字符串中的字符顺序反转,并返回结果。
要求:
- 字符串
s
不为空,且长度不超过 10^5。
#include <stdio.h>
#include <string.h>
void reverseString(char* s) {
int left = 0; // 左指针指向字符串开头
int right = strlen(s) - 1; // 右指针指向字符串末尾
while (left < right) {
char temp = s[left]; // 使用临时变量进行字符交换
s[left] = s[right];
s[right] = temp;
left++; // 移动指针
right--;
}
}
int main() {
char s[] = "Hello, World!";
printf("反转前的字符串:%s\n", s);
reverseString(s);
printf("反转后的字符串:%s\n", s);
return 0;
}
解析:
该问题要求将给定字符串 s
中的字符顺序进行反转。解决这个问题可以使用双指针法。首先,定义两个指针 left
和 right
,分别指向字符串的开头和末尾。通过交换 left
和 right
指针指向的字符,实现字符顺序的反转。在每次交换后,将 left
指针向右移动一位,将 right
指针向左移动一位,直到两个指针相遇或交叉。最后输出反转后的字符串。在主函数中,测试了给定的字符串 s
,并输出反转前和反转后的结果。
通过使用双指针法,可以在一次遍历内完成字符串的反转,时间复杂度为 O(n),其中 n 为字符串的长度。该方法不需要使用额外的空间,具有较高的效率。
50.给定一个非负整数 num
,编写一个函数 isPerfectSquare
,判断该整数是否是完全平方数。
要求:
- 非负整数
num
的范围为 [0, 2^31 - 1]。
#include <stdio.h>
#include <stdbool.h>
bool isPerfectSquare(int num) {
long left = 0; // 左边界为0
long right = num; // 右边界为num
while (left <= right) {
long mid = left + (right - left) / 2; // 二分查找的中间值
long square = mid * mid; // 计算中间值的平方
if (square == num) {
return true; // 找到完全平方数,返回true
} else if (square < num) {
left = mid + 1; // 中间值的平方小于num,调整左边界
} else {
right = mid - 1; // 中间值的平方大于num,调整右边界
}
}
return false; // 没有找到完全平方数,返回false
}
int main() {
int num = 16;
if (isPerfectSquare(num)) {
printf("%d 是完全平方数\n", num);
} else {
printf("%d 不是完全平方数\n", num);
}
return 0;
}
解析:
该问题要求判断给定的非负整数 num
是否是完全平方数。解决这个问题可以使用二分查找法。定义两个边界 left
和 right
,初始时,left
为0,right
为 num
。通过二分查找的方式,不断缩小边界范围。在每次查找中,计算中间值 mid
的平方,与 num
进行比较。若平方等于 num
,则说明 num
是完全平方数,返回 true
。若平方小于 num
,则将左边界 left
调整为 mid + 1
。若平方大于 num
,则将右边界 right
调整为 mid - 1
。重复上述步骤,直到找到完全平方数或边界相交。最后返回 false
,表示没有找到完全平方数。在主函数中,测试了给定的非负整数 num
,并输出结果。
使用二分查找法可以有效地缩小搜索范围,时间复杂度为 O(logn),其中 n 为给定的非负整数 num
。通过不断调整边界,快速确定是否存在完全平方数。