1006. 笨阶乘 - leetcode刷题(C++)

一、题目

1006. 笨阶乘

二、分析

  1. 常规做法,当成一个循环表达式,每4步为一个周期。那么采用栈记录每个乘除运算后的结果,最后通过遍历栈将栈内元素加起来。
10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1 = 12
--------以10为例---栈空间变化(左侧为栈底)---------
10:10
9: 90 	 			// 10出栈,10*9入栈
8: 11				// 90出栈,90/8入栈(11)
7: 11 7			// 直接入栈7
6: 11 7 -6			// 直接入栈-6
5: 11 7 -30		// -6出栈,(-6)*5入栈(-30)
4: 11 7 -7			// -30出栈,(-30)/4入栈(-7)
3: 11 7 -7 3		// 直接入栈3
2: 11 7 -7 3 2		// 直接入栈2
1: 11 7 -7 3 2		//2出栈,2*1入栈(2)
  1. 既然有周期性,就一定有规律。可以直接用函数式表示!
    运算顺序是乘,除,加,减,比如10*9/8+7-6,先不看后面的减法,直接看前3项,也就是n*(n-1)/(n-2)
    n ( n − 1 ) n − 2 = n + 1 + 2 n − 2 = n + 1 + 1 n 2 − 1 \frac{n(n-1)}{n-2}=n+1+\frac{2}{n-2}=n+1+\frac{1}{\frac{n}{2}-1} n2n(n1)=n+1+n22=n+1+2n11
    因为是整数运算,右边分式,当 n 2 − 1 > 1 \frac{n}{2}-1>1 2n1>1,即 n > 4 n>4 n>4时,此项等于0,那么三项结果等于n+1。比如上边提到的10*9/8 = 10+1 = 11
  • 对于N<=4时,单独讨论;
  • 对于N>4时:乘和除后边两个运算(或者说后边两个),是加(n-3)和减(n-4),那么 ( n − 3 ) − ( n − 4 ) ( n − 5 ) n − 6 = ( n − 3 ) − ( n − 4 + 1 ) = 0 (n-3) - \frac{(n-4)(n-5)}{n-6} = (n-3) - (n-4+1) = 0 (n3)n6(n4)(n5)=(n3)(n4+1)=0,也就是说,4个为一组,就可以消为0。

那么只需要知道N通过消零操作后,后边还剩余几个操作,就能直接得出结果。首先要明确两点:
1.最前边三个数 n ∗ ( n − 1 ) / ( n − 2 ) = ( n + 1 ) n*(n-1)/(n-2) = (n+1) n(n1)/(n2)=(n+1),是不能消除的,因为没有(n+1)减去之。
2.最后(<=4)的4个数不能消,因为不满去化简条件(严格来说应该是乘数<4时,这里只取大概值)。

  • N%4=0:N+1
    在这里插入图片描述前三个不能消,后4个不能消,那么剩余的5个数,可以通过消0去掉前边4个,剩余一个数:5,结果等于n+1+ 0 +5-4*3/2+1 = n+1
  • N%4=1:N+2
    在这里插入图片描述
  • N%4=2:
    在这里插入图片描述
  • N%4=3:
    在这里插入图片描述
    这样麻烦的去找规律,有什么优势嘛?首先,这个是从数学问题过渡过来的,建议了解一下;其次,时间复杂度从 O ( n ) O(n) O(n)降到了 O ( 1 ) O(1) O(1)

三、代码

class Solution {
public:
    int clumsy(int N) {
        int M = N;
        stack<int> stk;
        stk.push(N);
        N--;
        for(int i = 0; i < M-1; i ++){
            int temp;
            switch(i % 4){
                case 0:
                	// 当前元素 × 栈顶元素
                    temp = stk.top();
                    stk.pop();
                    stk.push(temp * N);
                    break;
                case 1: 
                	// 栈顶元素 ÷ 当前元素
                    temp = stk.top();
                    stk.pop();
                    stk.push(temp / N);
                    break;
                case 2: 
                	//正数直接入栈,最后再加到总和里
                    stk.push(N);
                    break;
                case 3:
                	//负数,将其相反数入栈,最后再加到总和里
                    stk.push(-N);
                    break;
            }
            N--;
        }
        int sum = 0;
        while(!stk.empty()){
            sum += stk.top();
            stk.pop();
        }
        return sum;
    }
};

执行用时:8 ms, 在所有 C++ 提交中击败了7.88%的用户
内存消耗:6.4 MB, 在所有 C++ 提交中击败了15.76%的用户

  1. 公式法
class Solution {
public:
    int clumsy(int N) {
        if (N == 1 || N == 2)
            return N;
        if (N == 3)
            return 6;
        if (N == 4)
            return 7;
        //大于4时,根据公式计算
        if (N % 4 == 0)
            return N + 1;
        if (N % 4 == 1 || N % 4 == 2)
            return N + 2;
        return N - 1;
    }
};

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值