面试中遇到递归算法

前几天在博客园看到有人面试时,遇到递归算法题,一时手痒就解了一个。顺便网上又找来几个,也实现了。给你们分享一下,开阔一下思路,没准你明天面试就能用上。面试

一、编写一个方法用于验证指定的字符串是否为反转字符,返回true和false。请用递归算法实现。(反转字符串样式为"abcdedcba")算法

二、一列数的规则以下: 一、一、二、三、五、八、1三、2一、34...... 求第30个是多少数组

三、一列数的规则以下: 一、十二、12三、123四、1234五、123456......,求第n个数的递归算法(n<=9)。函数

四、将一整数逆序,如987654321变为123456789。测试

五、一个射击运动员打靶,靶一共有10环,连开10枪打中90环的可能行有多少种?spa

以上的前提:不能用数组 或转成字符串处理,也不能用内置函数,如C#的幂函数(Math.Pow)3d

复制代码
 1 using System;
 2 
 3  namespace RecursionAlgorithms
 4 {
 5     class Program
 6     {
 7         private static bool fn1(ref string str, ref int from, ref int to)
 8         {
 9             if (from >= to) return true;
10             if (str[from++] != str[to--]) return false;
11             return fn1(ref str, ref from, ref to);
12         }
13         private static int fn2(int i)
14         {
15             return i <= 2 ? 1 : fn2(i - 2) + fn2(i - 1);
16         }
17         private static long fn3(long x, ref long n)
18         {
19             return (x <= 1) ? x : fn3(x - 1, ref n) + x * (n *= 10);
20         }
21         private static long fn4(long x, ref long n)
22         {
23             return (x < 10) ? x : fn4(x / 10, ref n) + (x % 10) * (n *= 10);
24         }
25         private static long fn5(int n, int sum)
26         {
27             if ((n == 1 && sum <= 10) || (sum == n * 10)) return 1;
28             if (sum > n * 10 || sum < 0) return 0;
29             long ok = 0;
30             for (int i = 0; i <= 10; i++)
31             {
32                 ok += fn5(n - 1, sum - i);
33             }
34             return ok;
35         }
36 
37         static void Main(string[] args)
38         {
39             string[] strs = { "", "a", "aa", "aba", "abba", "abcba", "ab", "abc", "abca" };
40             for (int i = 0; i < strs.Length; i++)
41             {
42                 string str = strs[i];
43                 int from = 0, to = str.Length - 1;
44                 Console.WriteLine("{0} is {1}", str, fn1(ref str, ref from, ref to));
45             }
46             for (int i = 1; i <= 30; i++) Console.Write("{0}:{1} \t", i, fn2(i));
47             long n = 1, m = 1, t = 0;
48             for (int i = 0; i <= 9; i++, n = m = 1)
49             {
50                 Console.Write("\n {0} ==> {1}", t = fn3(i, ref n), fn4(t, ref m));
51             }
52             Console.WriteLine("\n{0}种可能性", fn5(10, 90));
53         }
54     }
55 }
复制代码

测试一下:code

递归算法颇有意思的,并非说函数调用自身就必定是递归算法。有一次我作面试官,有一童鞋在一道简单的递归函数中,还用到了for循环,当场被我Pass(固然还有其余因素)blog

总结一下递归算法的解题思路:递归

首先步骤分解,写出最后一次递归(n=1)的计算公式,而后是倒数第二次(n=2),n=3....,最后概括出递归算法

如第二题:fn(1)=1;f(2)=1;f(3)=f(1)+f(2);----> f(n)=f(n-2)+f(1),那么很容易就写出这个递归函数

f(n)={n<=2?1:fn(n-2)+f(n-1)}

再如第五题:
递归函数定义:f(n,sum),n:轮次,sum:本轮及本轮以后应打中的总环数,返回值0表明一次失败的组合,返回值大于0则表明知足题设状况的组合数量。
f(1,sum),sum<0||sum>10,则返回0;
                sum<=10,这说明最后一枪只要打中sum环,就能知足题设,返回1,即一次组合状况
f(2,sum),sum<0||sum>20,则返回0;
                sum==20,这说明最后两枪只要打都中10环,就能知足题设,返回1
                sum<20,若是倒数第二枪打中x环[0,10],最后一枪打中sum-x环,也就能知足题设,成功状况累加
注意这里,上一句就能够描述为:当本轮打中x环的状况下,后几轮能打中sum-x环的状况能有几种,也即f(n-1,sum-x)种状况
我这个递归算法中,还能够加上一个数组参数用来记录前几轮的中靶状况,这样就能打印出每种组合
在递归算法中,当递归层次很深时,要考虑空间复杂度,尽可能减小新变量,因此个人算法中,多用了ref方式。在面试能够忽略这种状况,加快解题速度。
另外,多数递归算法均可以拆解成非递归的循环算法,由于这样会减小递归函数的入栈出栈。在实际运用中,要综合考虑运行工况(CPU、内存、算法被调用的频度,递归层数等),也就是空间与时间的取舍。
相关文章
相关标签/搜索