1006. 笨阶乘

1006. 笨阶乘

LeetCode题目:1006. 笨阶乘

我的思路1

  • 举个🌰,对于 N = 10 N=10 N=10,结果是 12 12 12,计算顺序如下: 12 = 10 ∗ 9 / 8 + 7 − 6 ∗ 5 / 4 + 3 − 2 ∗ 1 12 = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1 12=109/8+765/4+321
  • 显然,可以四个一组,将数字1~10分为(10,9,8,7),(6,5,4,3),(2,1)三组。对于前面的个数为4的组,显然,可以直接运算。对于最后一组,特殊处理即可。
  • 注意,任意两个组之间的运算符是减号。但是第一个组前面的符号应该是正号。
    • +(10,9,8,7),-(6,5,4,3),-(2,1)

根据上述思路,可以写出AC代码:

class Solution {
public:
    int clumsy(int N) {
        int n = N / 4;
        int ret = 0;
        for (int i = 0; i < n; i ++){ // 对个数为4的组进行处理
            int a = N - i * 4;
            int b = N - i * 4 - 1;
            int c = N - i * 4 - 2;
            int d = N - i * 4 - 3;
            int ans = a * b / c;
            if (ret == 0){ // 第一次运算符号为正
                ret += ans;
            }else{ // 组之间的符号为负
                ret -= ans; 
            }
            ret += d;

        }
        int sign = n == 0 ? 1 : -1; // 有没有个数为4的组
        int m = N % 4;
        if (m == 3){
            ret += sign * (3 * 2 / 1);
        }else if (m == 2){
            ret += sign * (2 * 1);
        }else if (m == 1){
            ret += sign * 1;
        }
        return ret;
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.8 MB, 在所有 C++ 提交中击败了83.64%的用户

  • 复杂度分析
    • 时间复杂度: O ( N ) O(N) O(N)。一个for循环,来不及解释了。
    • 空间复杂度: O ( 1 ) O(1) O(1)。只用到了可数个变量。

我的思路2

经验告诉我,这题可以 找规律
我们使用思路1的代码,我们使用Codeblocks打印前100项的结果:

#include<bits/stdc++.h>
using namespace std;
class Solution {
    ... // 思路1代码
};

int main(){
    Solution s;
    for (int i = 1; i <= 100; i ++){
        cout << i << "   " << s.clumsy(i) << "   " << s.clumsy(i) - i << endl;
    }
    return 0;
}

console输出:

1   1   0
2   2   0
3   6   3
4   7   3
5   7   2
6   8   2
7   6   -1
8   9   1
9   11   2
10   12   2
11   10   -1
12   13   1
13   15   2
14   16   2
15   14   -1
16   17   1
17   19   2
18   20   2
19   18   -1
20   21   1
21   23   2
22   24   2
23   22   -1
24   25   1
25   27   2
26   28   2
27   26   -1
28   29   1
29   31   2
30   32   2
31   30   -1
32   33   1
33   35   2
34   36   2
35   34   -1
36   37   1
37   39   2
38   40   2
39   38   -1
40   41   1
41   43   2
42   44   2
43   42   -1
44   45   1
45   47   2
46   48   2
47   46   -1
48   49   1
49   51   2
50   52   2
51   50   -1
52   53   1
53   55   2
54   56   2
55   54   -1
56   57   1
57   59   2
58   60   2
59   58   -1
60   61   1
61   63   2
62   64   2
63   62   -1
64   65   1
65   67   2
66   68   2
67   66   -1
68   69   1
69   71   2
70   72   2
71   70   -1
72   73   1
73   75   2
74   76   2
75   74   -1
76   77   1
77   79   2
78   80   2
79   78   -1
80   81   1
81   83   2
82   84   2
83   82   -1
84   85   1
85   87   2
86   88   2
87   86   -1
88   89   1
89   91   2
90   92   2
91   90   -1
92   93   1
93   95   2
94   96   2
95   94   -1
96   97   1
97   99   2
98   100   2
99   98   -1
100   101   1

Process returned 0 (0x0)   execution time : 0.377 s
Press any key to continue.
  • 可以看到从第5项开始, c l u m s y ( i ) − i clumsy(i) - i clumsy(i)i开始以2 2 -1 1的规律循环。

因此,可以写出AC代码:

class Solution {
public:
    int clumsy(int N) {
        if (N == 1){
            return 1;
        }else if (N == 2){
            return 2;
        }else if (N == 3){
            return 6;
        }else if (N == 4){
            return 7;
        }
        // 2 2 -1 1
        int m = N % 4;
        if (m == 1 || m == 2){
            return N + 2;
        }else if (m == 3){
            return N - 1;
        }else if (m == 0){
            return N + 1;
        }
        return -1; // 不会执行到这里。
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.9 MB, 在所有 C++ 提交中击败了51.51%的用户

  • 复杂度分析:

    • 时间复杂度: O ( 1 ) O(1) O(1).
    • 空间复杂度: O ( 1 ) O(1) O(1).
  • 证明:略。数学不好😣,我猜应该可以使用数学归纳法证明。

证明:思路2

在参考了其他人的证明后,发现证明其实并不难。

写出通用表达式: f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)
显然,我们是以4个为一组写出上述表达式的,因此,最后一项需要讨论。
如果n % 4 == 0,显然,最后一项是 4 ∗ 3 / 2 + 1 4 * 3 / 2 + 1 43/2+1,因此, f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … + 9 − 8 ⋅ 7 6 + 5 − 4 ⋅ 3 2 + 1 f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots + 9 - \frac {8\cdot7}{6} + 5 - \frac {4 \cdot 3} 2 + 1 f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)+9687+5243+1
进行数学运算: f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … + 9 − 8 ⋅ 7 6 + 5 − 4 ⋅ 3 2 + 1 = ( n − 2 + 2 ) ( n − 2 + 1 ) n − 2 + ( n − 3 ) − ( n − 6 + 2 ) ( n − 6 + 1 ) n − 6 + ( n − 7 ) − … + 9 − 8 ⋅ 7 6 + 5 − 4 ⋅ 3 2 + 1 = ( n − 2 ) + 3 − 2 n − 2 + ( n − 3 ) − [ ( n − 6 ) + 3 − 2 n − 6 ] + ( n − 7 ) − … + 9 − 8 ⋅ 7 6 + 5 − 4 ⋅ 3 2 + 1 = n + 1 + ( n − 3 ) − ( n − 3 ) + ( n − 7 ) − … + 9 − 8 ⋅ 7 6 + 5 − 4 ⋅ 3 2 + 1 = n + 1 + 5 − 6 + 1 = n + 1 f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots + 9 - \frac {8\cdot7}{6} + 5 - \frac {4 \cdot 3} 2 + 1 \\ = \frac {(n - 2 + 2)(n - 2 + 1)} {n-2} + (n - 3) - \frac {(n - 6 + 2)(n - 6 + 1)}{n - 6} + (n - 7) - \ldots + 9 - \frac {8\cdot7}{6} + 5 - \frac {4 \cdot 3} 2 + 1 \\ = (n-2) + 3 - \frac {2}{n-2} + (n - 3) - [(n-6) + 3 - \frac {2}{n-6}] + (n - 7) - \ldots + 9 - \frac {8\cdot7}{6} + 5 - \frac {4 \cdot 3} 2 + 1 \\ = n + 1 + (n - 3) - (n-3) + (n - 7) - \ldots + 9 - \frac {8\cdot7}{6} + 5 - \frac {4 \cdot 3} 2 + 1 \\ = n + 1 + 5 - 6 + 1 \\= n + 1 f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)+9687+5243+1=n2(n2+2)(n2+1)+(n3)n6(n6+2)(n6+1)+(n7)+9687+5243+1=(n2)+3n22+(n3)[(n6)+3n62]+(n7)+9687+5243+1=n+1+(n3)(n3)+(n7)+9687+5243+1=n+1+56+1=n+1

  • 注意,最后的 5 − 4 ⋅ 3 2 5 - \frac{4 \cdot 3} 2 5243不能被约去。

同理,如果n % 4 == 1,显然,最后一项是 1 1 1,因此,此时, f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … − 9 ⋅ 8 7 + 6 − 5 ⋅ 4 3 + 2 − 1 = n + 1 + 2 − 1 = n + 2 f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots - \frac {9 \cdot 8} 7 + 6 - \frac {5 \cdot 4} 3 + 2 - 1 \\= n + 1 + 2 - 1 \\=n + 2 f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)798+6354+21=n+1+21=n+2

如果n % 4 == 2,最后一项是 2 ∗ 1 2*1 21。此时, f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … − 7 + 6 ⋅ 5 4 + 3 − 2 ⋅ 1 = n + 1 + 3 − 2 = n + 2 f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots - 7 + \frac {6 \cdot 5} 4 + 3 - 2\cdot1 \\= n + 1 + 3 - 2 \\=n + 2 f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)7+465+321=n+1+32=n+2

如果n % 4 == 3,最后一项是 3 ∗ 2 / 1 3*2/1 32/1。此时, f ( n ) = n ( n − 1 ) n − 2 + ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 + ( n − 7 ) − … − 8 + 7 ⋅ 6 5 + 4 − 3 ⋅ 2 1 = n + 1 + 4 − 6 = n − 1 f(n) = \frac {n(n-1)}{n-2} + (n-3) - \frac {(n-4)(n-5)}{n-6} + (n-7) - \ldots - 8 +\frac {7 \cdot 6} 5 + 4 - \frac{3\cdot2}{1} \\= n + 1 + 4 - 6 \\=n - 1 f(n)=n2n(n1)+(n3)n6(n4)(n5)+(n7)8+576+4132=n+1+46=n1


2021.4.1 愚人节快乐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值