一、题目
二、分析
- 常规做法,当成一个循环表达式,每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)
- 既然有周期性,就一定有规律。可以直接用函数式表示!
运算顺序是乘,除,加,减,比如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} n−2n(n−1)=n+1+n−22=n+1+2n−11
因为是整数运算,右边分式,当 n 2 − 1 > 1 \frac{n}{2}-1>1 2n−1>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 (n−3)−n−6(n−4)(n−5)=(n−3)−(n−4+1)=0,也就是说,4个为一组,就可以消为0。
那么只需要知道N通过消零操作后,后边还剩余几个操作,就能直接得出结果。首先要明确两点:
1.最前边三个数
n
∗
(
n
−
1
)
/
(
n
−
2
)
=
(
n
+
1
)
n*(n-1)/(n-2) = (n+1)
n∗(n−1)/(n−2)=(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%的用户
- 公式法
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%的用户