剑指offer 9.8
求1+2+...n/设计机械累加器
LCR 189. 设计机械累加器 - 力扣(LeetCode)
解题思路:
因为题目要求不允许使用循环判断等语句,因此不能在递归条件中使用if来判断当前是否target==0
但是我们可以运用到短路的策略,即&&只有第一个条件满足时他才会去判断第二个条件,如果第一个条件不满足将会直接退出。所以这个就可以起到一个判断的作用。
再解释一下为什么可以共用一个target,即返回值也为target,判断条件也为target
因为这里的target是以值传递传递进来的,所以每一次递归调用都会创建自己的栈帧,每个栈帧中的target都是相互独立的,因此不会互相影响。如果是以引用的形式传入就不行,因为所有栈帧中都是共享同一个target
int mechanicalAccumulator(int target) {// //利用短路,只有当第一个条件满足时,才会去判断第二个条件,如果第一个条件不满足就直接返回// target>1&&(target += mechanicalAccumulator(target-1));// return target;return target==0?0:target+mechanicalAccumulator(target-1);}
参考题解区中大佬的代码:
https://leetcode.cn/problems/qiu-12n-lcof/solutions/208315/mian-shi-ti-64-qiu-1-2-nluo-ji-fu-duan-lu-qing-xi-/comments/1095879/
大佬这里利用的是C++中的构造函数,通过构造一个数组,其中每一个元素都会调用其构造函数,在类中定义两个static成员来完成累加的操作。
class Solution {
public:static int tmp;static int sum;Solution(){++tmp;sum += tmp;}void init(){tmp = 0;sum = 0;}int mechanicalAccumulator(int target) {// //利用短路,只有当第一个条件满足时,才会去判断第二个条件,如果第一个条件不满足就直接返回// target>1&&(target += mechanicalAccumulator(target-1));// return target;// return target==0?0:target+mechanicalAccumulator(target-1);init();Solution* res = new Solution[target];delete[] res;return sum;}
};
int Solution::tmp = 0;
int Solution::sum = 0;
按规则计算统计结果
LCR 191. 按规则计算统计结果 - 力扣(LeetCode)
前缀和解题思路:
关键点就在于我们应该怎么样去统计当前数字左右两边的数的乘积,所以单独用一边前缀和是不行的。
这里的思路是:先声明出一个返回数组,进行第一次的从左到右的统计,也就是统计当前数字左边的所有数的乘积,这是第一次前缀和
第二次便是从倒数第二个位置开始,因为最后一个位置的值已经在第一轮的时候计算完了,所以应该从倒数第二个位置开始统计当前数字右边的所有的数的乘积。
这样就完成了,统计一个数字除自身以外的所有数的乘积
vector<int> statisticalResult(vector<int>& arrayA) {if(arrayA.size()==0) return{};vector<int> res(arrayA.size(), 1);res[0] = 1;//前缀和,从左往右计算//第一次循环只统计的了当前数字左边的乘积for(int i = 1;i<arrayA.size();i++){res[i] = res[i-1]*arrayA[i-1];}//从右往左计算//因为第一次循环已经计算了最后一个数字因此这里不需要重新计算最后一个数字了//第二次循环便是统计当前数的从右到左的乘积并结合第一次循环后的结果int tmp = 1;for(int i = arrayA.size()-2;i>=0;i--){tmp *= arrayA[i+1];res[i] *= tmp;}return res;}
把字符串转换成整数
LCR 192. 把字符串转换成整数 (atoi) - 力扣(LeetCode)
解题思路:
根据题目要求,要求忽略前导空格,并且要分辨正负号,并且要处理当转成的数字超过int的最大或最小的数应该直接返回int中的最大和最小的数
所以思路是这样的,声明一个变量,代表遍历的位置,先去判断是否有空格,有空格便将pos起始位置向前移动。
去除空格后便是判断正负号,并将判断结果收集到结果sign中
最后就是正式的循环区构造结果,关键就在于,判断当前的数是否超过最大或最小的数,这里用的是声明一个bin让他为INT_MAX/10后的结果,因为我们是要在组合前提前进行判断,如果当前的res已经大于bin了,无论接下来是什么都一定会超过的直接根据符号位去返回对应的值。如果当前的数等于了bin,就需要判断这个字符的值,如果大于7,则也是溢出的
这里有个问题就是INT_MIN应该是-2147483648,应该是可以等于8的,为什么大于7就直接返回,看了题解去中的回答,意思是,C++中不能直接对一个int型变量赋值为-2147483648,原因是在处理的过程中,会将符号和数字进行分割,会导致超过INT_MAX2147483647,所以这里我们是如果当前的字符大于7也要进行返回
int myAtoi(string str) {if(str.size()==0) return 0;int pos = 0;//遍历字符串的位置int sign = 1;//符号位int res = 0;//最后的返回值int bin = INT_MAX/10;//最大边界,在拼接前进行处理while(str[pos]==' '){pos++;}//判断符号if(str[pos]=='-') sign = -1;if(str[pos]=='-'||str[pos]=='+') pos++;for(int i = pos;i<str.size();i++){if(str[i]<'0'||str[i]>'9') break;if(res>bin||res==bin&&str[i]>'7'){return sign == 1? INT_MAX:INT_MIN;}res = res*10+(str[i]-'0');}return res*sign;}