这是博主在某一份工作面试中遇到的一个面试题,因为那会还是自己第一份工作的面试,不想白白浪费,于是问了我一个在香港大学计算机研究生的一位哥哥,然后我哥哥帮我做的,时隔一年了,博主还在游戏行业中翻滚,回想起这份代码觉得十分有意思,也很厉害(对博主而言),于是今天拉出来,一是为了留个纪念,二是为了能和各位大佬们互相学习。
话不多说,博主先把面试题拉出来。
一、算法题:
b=fun(a)
函数fun把a变换到b,每次任意选择下面三种方式之一:
1:b=a * 2
2:b=a - 1
3:b=a + 1
写一个算法,用最少的fun调用次数,来实现变换,并且输出变换序列
trans(2, 5)
第一次变换
4= 2 * 2
第二次变换
5= 4 + 1
然后就搞定了
***************************************************
请测试trans(43, 103)
输出结果:
43 103
need 10 steps
step 1 : 43 -> 44
step 2 : 44 -> 45
step 3 : 45 -> 46
step 4 : 46 -> 47
step 5 : 47 -> 48
step 6 : 48 -> 49
step 7 : 49 -> 50
step 8 : 50 -> 51
step 9 : 51 -> 102
step 10 : 102 -> 103
没有明白题目意思的老铁们不要着急,其实很简单,就是从 a -> b ,使用 +1, -1, *2,这3个算法的其中一个,
一直要得到b结果为止,要求步数最少,也就是最优解法
比如 2 -> 11
step 1: 2 *2 =4
step 2: 4 +1 = 5
step 3: 5 *2 =10
step 4: 10 +1 = 11
类似这种
刚开始面对这道题的我来说,是懵逼的。。那时候哪知道什么 贪心 回溯 分治 动态规划 。。。。
虽然现在也不是很懂,,哈哈哈
大家可以先不看答案,反正思路我也大概说了,大家可以自己做着玩,,
我哥哥的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestPro03
{
class Program
{
static void Main(string[] args)
{
int a = 101;
int b = 2;
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
trans(a, b);
print(a, b);
stopwatch.Stop();
TimeSpan timeSpan = stopwatch.Elapsed;
Console.WriteLine("milliSeconds : " + timeSpan.Milliseconds);
Console.ReadKey();
}
static List<int> res = new List<int>(); //存储每一步变换后的元素
static void trans(int st, int ed) //变换
{
Dictionary<int, int> myDic = new Dictionary<int, int>();//用三种方法的结果来当key保存之前的值
List<int> vis = new List<int>();//存储所有出现过的结果
List<int> que = new List<int>();//存储参与运算的值
myDic[st] = st;
que.Add(st);
vis.Add(st);
while (que.Count != 0) //存储
{
int now = que.First<int>();
que.Remove(que.First<int>());
//只参与一次
int next1 = fun1(now);
int next2 = fun2(now);
int next3 = fun3(now);
int next4 = fun4(now) - (int)fun4(now) == 0 ? (int)fun4(now) : st;
if (!vis.Contains(next1)) //判断结果是否存在于集合之中
{
vis.Add(next1);
myDic[next1] = now;
if (next1 == ed) break;//是否到达最终结果
que.Add(next1);
}
if (!vis.Contains(next2))
{
vis.Add(next2);
myDic[next2] = now;
if (next2 == ed) break;
que.Add(next2);
}
if (!vis.Contains(next3))
{
vis.Add(next3);
myDic[next3] = now;
if (next3 == ed) break;
que.Add(next3);
}
if (!vis.Contains(next4))
{
vis.Add(next4);
myDic[next4] = now;
if (next4 == ed) break;
que.Add(next4);
}
}
int k = ed;
while (true) //最终用到的元素
{
if (k == myDic[k]) break;
res.Add(k);
k = myDic[k];
}
}
static void print(int st, int ed) //输出
{
Console.WriteLine("need {0} steps", res.Count);
int pre = st;
int t = 0;
int count = res.Count;
for (int i = count - 1; i >= 0; i--)
{
int now = res[i];
t++;
string str = "step" + t + ":" + pre + "->" + now;
Console.WriteLine(str);
pre = now;
}
}
static int fun1(int a) //乘
{
int b = a * 2;
return b;
}
static int fun2(int a) //减
{
int b = a - 1;
return b;
}
static int fun3(int a) //加
{
int b = a + 1;
return b;
}
static double fun4(int a) //除
{
double b = (double)a / 2;
return b;
}
}
}
其实这份代码我哥哥原本给我时候是一份C++的代码,被我硬生生的翻译成了C#,整体我已经大概实验过了,确实是最优的,有没有没有考虑的地方我就不知道了。
如果大家有什么可以教博主的地方,还请大家不吝赐教,博主是个新程序猿,很菜鸡的那种
很希望能和大家一起讨论学习