搜狗2020.9.8算法笔试(第一题)

题目描述:斐波那切数列f(n+2)=f(n+1)+f(n)

给一个输入:2<=x<=2^32,给出所有可能的斐波那切数列中的位置。(描述不太准确,看测试用例)

测试用例:输入

3

输出:

3  2

4   1   

意思是x的位置在3的数列有两种,在4的数列有1种(输出的位置小于3的不算(即不能以x作为数列的前两项))

他们分别是 1 1 2 3;1 2 3;2 1 3;  (然后按位置较小的顺序输出)

直接暴力循环所有可能性只有10%的正确率,提示时间超时(所以我也不确定我的代码是否正确,贴上来,可以讨论下)

#include<iostream>
#include<map>
#include<vector>
using namespace std;

int main()
{
	long long x;
	cin >> x;
	map<long long, int>mp;
	for (long long i = 1; i < x; i++)
	{
		for (long long j = 1;i+j<=x; j++)
		{
			long long pre1 = i;
			long long pre2 = j;
			long long sum = pre1+pre2;
			long long num = 2;
			while (sum < x)
			{
				num++;
				pre1 = pre2;
				pre2 = sum;
				sum = pre1 + pre2;
			}
			if (sum == x)
			{
				num++;
				if (num >= 3)
				{
					mp[num]++;
				}
				
			}
		}
	}
	map<long long, int>::iterator it=mp.begin();
	for (;it!=mp.end();it++)
	{
		cout << it->first << " " << it->second << endl;
	}
	system("pause");
	return 0;
}

去牛大神客上搜了搜回答,给大神跪了。

直接复制下的解释:

作者:莫得感情的拒信收割机
链接:https://www.nowcoder.com/discuss/250292
来源:牛客网

大概思想是,如果给的数是x,假设前一个数为y,那么倒数第三个数是x-y,倒数第四个数是2y-x,然后保证每个数>0,可以得到m的区间。3个数m介于1到x之间,4个数的话y介于1/2x到x之间,5个数的话y介于1/2x到2/3x之间,注意都是开区间。会发现那个分数的分子分母是斐波拉契数列,然后更新就好了。如果y取不到了,就停止循环.(侵权删)

想了很久,解释一下吧。

我以数组res存放每次计算的结果。

假设只有三个数即,x-y,  y, x.

则可以推出 \left\{\begin{matrix} x>0\\ y>0\\ y<x \end{matrix}\right.,所以y的所有可能取值为1<=y<x,也就是res[3]=x-1;

再假设有四个数:2y-x , x-y, y , x

则可以推出\frac{1}{2}x<y<x,所以  res[4]=x-\frac{1}{2}x-1(因为是开区间所以减1)

再假设有五个数:2x-3y ,2y-x , x-y, y , x

则可以推出\frac{1}{2}x<y<\frac{2}{3}x,所以  res[5]=\frac{2}{3}x-\frac{1}{2}x-1

然后大神说分子分母的系数是斐波那切数列序列

有点蒙,又计算了一个

再假设有六个数:5y-3x,2x-3y ,2y-x , x-y, y , x

则可以推出\frac{3}{5}x<y<\frac{2}{3}x,所以  res[6]=\frac{2}{3}x-\frac{3}{5}x-1

然后整理一下系数的关系

x-1;

x-\frac{1}{2}x-1

\frac{2}{3}x-\frac{1}{2}x-1

\frac{2}{3}x-\frac{3}{5}x-1

以下是我总结的比较笨的规律啊

第一个首先更新迭代时有一项是保持不变的,先是第一项,然后第二项(当更新奇数位置时第一项更新,更新偶数位置相反)

第二个大神给出的:

首先初始化res[3]=x-1;

然后第一个等式的x前的系数可以看做\frac{1}{1}

更新下一组参数时保持第一项不变,为\frac{1}{1}x,(此时数列为1 1)第二项的分子更新为f(n+1),即1,而分母更新为f(n+2)=f(n)+f(n+1) 即2 ,然后更新数列(1 1 2),

再更新下一组参数时,保持第二项不变,更新第一项,分子为分f(n+1)=2;分母为f(n)+f(n+1)=3,更新数列(1 1 2 3)

再更新下一组参数时,保持第一项不变,更新第二项,分子为分f(n+1)=3;分母为f(n)+f(n+1)=5,更新数列(1 1 2 3 5)

那么推测res[7]的表达式:

保持第二项不变,更新第一项,分子为分f(n+1)=5;分母为f(n)+f(n+1)=8,更新数列(1 1 2 3 5 8)

即表达式应该为:res[7]=\frac{5}{8}x-\frac{3}{5}x-1,

用数学推导一下:七个数的话数列应该为5x-8y, 5y-3x,2x-3y ,2y-x , x-y, y , x,结果正是\frac{3}{5}x<y<\frac{5}{8}x,往下就不推了:

以下是代码:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	long long x;
	cin >> x;
	vector<long long>res(10000);
	vector<long long>fn(10000);
	res[3] = x - 1;//结果输出,
	//fn[3] = 1;//可以用来保存中间计算的结果
	int num = x - 1;
	int pre1 = 1;//存放分子分母状态的序列
	int pre2 = 1;
	int i = 3;
	while (num > 0)
	{
		i++;
		if (i % 2 == 0)
		{
			//int c1 = (pre1 / pre2)*x;
			//int c2 = (pre2 / (pre1 + pre2))*x;测试用的,千万别写成这种形式
			num = (pre1*x / pre2) - (pre2 *x/(pre1 + pre2))-1;
			pre1 = pre2;
			pre2 = pre1 + pre2;
			if (num > 0)
			{
				res[i] = num;
			}
			else
			{
				break;
			}
		}
		else
		{
			num = (pre2 *x/(pre1 + pre2)) - (pre1*x / pre2) - 1;
			pre1 = pre2;
			pre2 = pre1 + pre2;
			if (num > 0)
			{
				res[i] = num;
			}
			else
			{
				break;
			}
		}
	}
	i = 3;
	while (res[i] > 0)
	{
		cout << i << " " << res[i] << endl;
		i++;
	}
	system("pause");
	return 0;
}

因为没有测试平台,不知道对不对,欢迎指正错误。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值