文章目录
- 1. Fibonacci数列 ⭐️
- 2. 替换空格 🌟
- 3. 找单身狗 💫
- 4. 模拟实现 atoi ✨
1. Fibonacci数列 ⭐️
做题链接:Fibonacci数列
Fibonacci数列是这样定义的:
F[0] = 0
F[1] = 1
for each i ≥ 2: F[i] = F[i-1] + F[i-2]
因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, …,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。
- 输入描述:输入为一个正整数N(1 ≤ N ≤ 1,000,000)
- 输出描述:输出一个最小的步数变为Fibonacci数"
示例:
- 输入:15
- 输出:2
思路:当 n 落在第一个斐波那契数的左边的时候似乎没有什么意义,它只有变成第一个斐波那契数的可能,没有最小步数。所以只有当 n 落在第一个斐波那契数和第二个斐波那契数的中间时,才求最少需要多少步可以变成斐波那契数。
- 如果 n 等于第二个斐波那契数,步数就等于0。
- 如果 n 小于第二个斐波那契数,分别求第一个斐波那契数和第二个斐波那契数分别减 n 的绝对值差,并比较大小。这里引用求绝对值的库函数abs,头文件 #include <math.h> 。当 abs(f1-n)<abs(f2 - n);则打印输出abs(f1-n)的值;反之则输出abs(f2-n)的值。
- 如果 n 不等于也不小于第二个斐波那契数,n 大于第二个斐波那契数的时候,我们这边用赋值进行下一组数的计算。
代码如下:
#include <stdio.h>
#include <math.h>
int main()
{
int n = 0;
scanf("%d", &n);
int f1 = 0;
int f2 = 1;
int f3 = f1 + f2;
while (1)
{
if (n == f2)
{
printf("0\n");
break;
}
if (n < f2)
{
if (abs(f1 - n) < abs(f2 - n))
{
printf("%d\n", abs(f1 - n));
}
else
{
printf("%d\n", abs(f2 - n));
}
break;
}
//n>f2
f1 = f2;
f2 = f3;
f3 = f1 + f2;
}
return 0;
}
2. 替换空格 🌟
做题链接:替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
这里有的人就会想将空格替换成%20有什么意义呢?是不是太闲了呢?
当我们在百度搜索栏中输入We Are Happy就会看到地址栏里出现We%20Are%20Happy,在搜索链接里会将空格替换成%20,这是为什么呢?因为空格的ASCII码值是20。
当我们点击链接会发现这道题在牛客网是这样的,这种是接口型的OJ题目。
OJ题目分为两种:
- IO型:自己完成输入输出,包括 main 函数
- 接口型:只需要完成接口就可以了
接口型的OJ题目要假定 main 函数已经有了,并且调用了replaceSpace(),传递了何时的参数。
做题思路:
- char *str,int length 这句代码的意思是把 str 指向的字符串里的空格替换成20,str指向的字符串长度是length。
- 一个空格要被替换成%20,就是一个字符要变成3个字符,所以字符本质上要往后挪,遇到一个空格就要增长2个字符,假设有 n 个空格,字符串的长度就等于nx2+原字符串的长度。
- 给两个标记,end1 标记替换之前的字符串的最后一个元素,end2 标记替换之后的字符串的最后一个元素,在 end1 没有遇到空格之前,把 end1 标记的元素挪移到 end2 标记的位置之后,end1 和 end2 都向前挪动,当 end1 遇到空格后,end1 向前挪动一步,把 end2 标记的位置依次写入02%(从后往前赋值),在写的过程中,每写一个字符,end2 向前移动一步,循环这个过程,直到把所有空格替换完成,当 end1 和 end2 指向同一个元素时替换完成。
#include <stdio.h>
#include <string.h>
void replaceSpace(char* str, int length) {
int space_count = 0;//统计空格的个数
char* cur = str;
//*cur!=\0,开始遍历
while (*cur)
{
if (*cur == ' ')
space_count++;
cur++;
}
//计算end1,end2
char* end1 = str + length;
char* end2 = str + length + 2 * space_count;
while (end1 != end2)
{
if (*end1 != ' ')
{
*end2-- = *end1--;//后置--,先赋值再减
}
else
{
*end2-- = '0';//从后往前赋值
*end2-- = '2';
*end2-- = '%';
end1--;
}
}
}
int main()
{
char arr[40] = "We Are Happy";
int len = strlen(arr);
replaceSpace(arr, len);
printf("%s\n", arr);
return 0;
}
3. 找单身狗 💫
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
示例:
- 输入数组的为:1 2 3 4 5 1 2 3 4 6
- 输出:5 6
思路:
异或操作符^:相同为0;相异为1;异或操作符是支持交换律的。a^a = 0; 0^a = 0; 1^3^1 = 3; 1^1^3 = 3;
找一个单生狗 1 2 3 4 5 1 2 3 4,用异或操作符就能找出单生狗是5了。
找两个单生狗1 2 3 4 5 1 2 3 4 6,我们这里就需要给他分组,把5和6分到两个组里,每一个组里只有一个单生狗,其余的都是成对的。例如:A组:1 2 1 2 5;B组:3 4 3 4 6;或者A组 1 3 1 3 5;B组 2 4 2 4 6。怎样才能实现以上的分组你呢?5的二进制位101,6的二进制位110;5^6 = 011,异或的结果为011,证明他们的最低为和第二位都不相同。5的最低位是1,6的最低位是0;我们就将最低位为1的分到A组,最低位为0的分到B组。或者用第二位分组也可以。
分组思想:
- 计算5和6二进制中的哪一位为1(第n位)
- 以第n位为标准,第n位为1的放一组,第n位为0的放一组。
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
//所有数字异或
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
//ret 就是5^6的结果,二进制中一定有1
//计算ret的第几位是1
int pos = 0;
for (i = 0; i < 32; i++)
{
if ((ret >> i) & 1 == 1)
{
pos = i;
break;
}
}
//ret的pos位是1
//把arr数组中的每个元素的第pos位为1的数字异或在一起
int num1 = 0;
int num2 = 0;
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
num1 ^= arr[i];
}
else
{
num2 ^= arr[i];
}
}
printf("%d %d", num1, num2);
return 0;
}
4. 模拟实现 atoi ✨
atoi 把字符串转换成对应的数字
atoi的使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ret = atoi("123");
printf("%d\n", ret);
return 0;
}
模拟实现atoi
//模拟实现atoi会出现的情况
//my_atoi(NULL)//异常
//my_atoi("")//异常
//my_atoi(" +123")//正常
//my_atoi("-123")//正常
//my_atoi("123abc")//异常
//my_atoi("1111111111111111111111111")//异常
//my_atoi("-1111111111111111111111111")//异常
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
//枚举定义状态值
enum Status
{
VALID,//合法
INVALID //非法
};
enum Status status = INVALID;//定义一个全局的状态值为非法
//根据返回值判断是非法的还是合法的
int my_atoi(const char* str)
{
if (str == NULL)
{
return 0;
}
if (*str == '\0')
{
return 0;
}
//空白字符
while (isspace(*str))
{
str++;
}
int flag = 1;
if (*str == '+')
{
flag = 1;
str++;
}
else if (*str == '-')
{
flag = -1;
str++;
}
//处理数字字符
//123
long long ret = 0;
while (isdigit(*str))
{
ret = ret * 10 + flag * (*str - '0');
if (ret<INT_MIN || ret>INT_MAX)//值越界了
{
return 0;
}
str++;
}
if (*str == '\0')
{
status = VALID; //定义一个局部的状态值为合法
return (int)ret;
}
else
{
return (int)ret;
}
}
int main()
{
int ret = my_atoi(" -123");
if (status == VALID)
printf("合法转换:%d\n", ret);
else
printf("非法转换:%d\n", ret);
return 0;
}
本章到这里就结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话请给个三连支持一下吧!
Fighting!!!✊