腾讯实习生笔试编程题--数的分解

来源:互联网 发布:董成鹏抄袭知乎 编辑:程序博客网 时间:2024/04/30 10:53

原题如下:


如下示例:
1:共0种分解方法;
2:共0种分解方法;
3: 3 = 2 + 1 共1种分解方法;
4: 4 = 3 + 1 = 2 + 1 + 1 共2种分解方法;
5: 5 = 4 + 1 = 3 + 2 = 3 + 1 + 1 = 2 + 2 + 1 = 2 + 1 + 1 + 1 共5种分解方法;
6: 6 = 5 + 1 = 4 + 2 = 4 + 1 = 3 + 2 + 1 = 3 + 1 + 1 + 1 = 2 + 2 + 1 + 1 = 2 + 1 + 1 +1 + 1 共7种分解方法
依此类推,求一任意整数num有几种分解方法?
输入一个数字(1到90),输出该整数按如上示例的分解方法个数
如:
输入:2
输出:0
输入:3
输出:1
输入:5
输出:5


对于一个num>5,分解方法如下:
这里写图片描述
要求num的分解方法,可以把上表中的每一种情况(一列代表一种情况)的分解方法累加起来:
f( x ) 代表数x的分解方法数目,g( i )代表数i拆分成1或2的分解方法数目。
f( num ) = 1 + 1 + g( 1 ) + g( 2 ) + … + g( num-3 );
g( 1 ) = 1 : 1;
g( 2 ) = 2 : 2; 1,1;
g( 3 ) = 2 : 2,1; 1,1,1;
g( 4 ) = 3 : 2,2; 2,1,1; 1,1,1,1;
g( 5 ) = 3 : 2,2,1; 2,1,1,1; 1,1,1,1,1;
g( 6 ) = 4: 2,2,2; 2,2,1,1; 2,1,1,1,1; 1,1,1,1,1,1;
总结规律为把 i 拆尽可能多的2,然后把每一个2拆成两个1;所以对于 i 可以拆出 i/2(向下取整) 个2,故依次把每一个2拆成两个1可以得到 i/2 中分解方法,加上拆成2最多的情况(全2或者只有1个1),即得 g( i ) = i/2 +1
故:f( num ) = 2 + g( 1 ) + g( 2 ) + … + g( num-3 )
= 2 + ( 1/2 + 1 ) + ( 2/2 + 1 ) + .. + ( (num-3)/2 + 1 )
= 2 + (num-3) + ( 1 + 2 + … + (num-3) )/2
= num-1 + ( 1 + 2 + … + (num-3) )/2 (注意此处是的除法是向下取整)
即对于num的解法: f( 1 ) = f( 2 ) =0; f( 3 ) = 1; f( 4 ) = 2;
f ( num ) = num-1 + ( 1 + 2 + … + (num-3) )/2 (num >= 5, 注意此处是的除法是向下取整)

import java.util.Scanner;public class SplitNum1 {    private static int[] f = new int[91];    private static void calcu(){        f[0] = 0;        f[1] = 0;        f[2] = 0;        f[3] = 1;        f[4] = 2;        for(int i = 5; i < f.length; ++i){            f[i] = i - 1;            for(int j = 1; j <= i-3; ++j)                f[i] += j/2;        }    }    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int num;        calcu();        while( sc.hasNextInt() ){            num = sc.nextInt();            System.out.println( f[num] );        }    }}

这种解法的时间复杂度为O(n2),空间复杂度为O(n)。
计算每一个结果都要从1开始计算,所以时间复杂度比较大,考虑动态规划是否可以降低时间复杂度。
f( n+1 ) = (n+1) -1 + ( 1 + 2 + .. + (n+1 -4) + (n+1 -3))/2
= n-1 +1 +(1+2+…+n-3)/2 + (n+1-3)/2
= f( n ) + 1 + (n+1 -3)/2
= f( n ) + (n+1 -1)/2
因此f(num) 可以通过前一项的结果计算得出,从而可以将梅一项的计算复杂度降至O(1),使总时间复杂度降至O(1)。

import java.util.Scanner;public class SplitNum1 {    private static int[] f = new int[91];    private static void calcu2(){        f[0] = 0;        f[1] = 0;        f[2] = 0;        f[3] = 1;        f[4] = 2;        f[5] = 5;        for(int i = 6; i < f.length; ++i){            f[i] = f[i-1] + ( i-1 )/2;        }    }    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int num;        calcu2();        while( sc.hasNextInt() ){            num = sc.nextInt();            System.out.println( f[num] );        }    }}

另外一种思路:
这里写图片描述
当num>=6时,其分解方法f( num )是 :
(num-1, 1), (num-2, 2),计p1 = 2;
在(num-1)的每一种分解方法后面加1,计p2 = f( num-1 );
在(num-2)的分解方法中有且仅有1个1且有2的分解方法后面加2,计p3;
即可得到num的所有分解方法:
f( num ) = p1 + p2 + p3 = 2 + f( num - 1) + p3
计算p3:p3 = (num-1)/2 -2
f(num) = 2 + f(num-1) + (num-1)/2-2
= f(num-1) + (num-1)/2

0 0
原创粉丝点击