leetcode-数学总结

leetcode-412 -Fizz Buzz-(fizz bzz)-java
解法1(成功,6ms,较慢)
不用对数进行mod,直接设置mod参数,mod3,mod5,每次+1,到3,5,为0
其余剩余别人的做法是直接对i%3的做法

还有i变为string类型除了string.valueof(i) 还有i+""

leetcode-204-计数质数(count primes)-java
解法1 把每个数mod质数列表,如果没有mod为0的,则把这个数加入质数列表,如果质数>该数的开方+1,则不再检测,少了很多时间
但这个方法不好
解法2
使用见埃拉托色尼筛法。
好方法
说的都是对循环条件的处理:
如果要实现筛法,需要一个O(n)的数组来存储每一个数是不是素数,暂定为true,筛选,把不是素数的定为false,最终数组里为true的就是所有的素数了。如何筛选?p是素数,那么2p, 3p……一定不是素数。事实上,如果筛的是2p, 3p……那么考虑 2*3这个数,它被2筛了一次,又被3筛了一次,没有必要。可以这样筛选:对于每一个素数p,筛掉p^{2}, p^{2}+p, p^{2} + 2p……
并不需要对[2, n]的每一个数进行筛选,只需要对[2, \sqrt{n}]进行筛选,即可筛出所有不是素数的数。

这里做了两个优化,作为除数的设定为质数,count++,不用最后再找。
筛选非质数,直接选择2p, 3p…,而不是所有数mod p 来判断,减少判断次数

leetcode-32-3的幂(power of three)-java
计算是否为幂有几种办法
1 不断除以3,或者1不断乘以3进行比较
2 由于输入是int,正数范围是0-2 ^ 31,在此范围中允许的最大的3的次方数为3 ^ 19=1162261467,那么我们只要看这个数能否被n整除即可,这是最快的办法

3 利用对数的换底公式来做,高中学过的换底公式为logab = logcb / logca,那么如果n是3的倍数,则log3n一定是整数,我们利用换底公式可以写为log3n = log10n / log103,注意这里一定要用10为底数,不能用自然数或者2为底数,否则当n=243时会出错,原因请看这个帖子。现在问题就变成了判断log10n / log103是否为整数,在c++中判断数字a是否为整数,我们可以用 a - int(a) == 0 来判断

leetcode-13-罗马数字转整数(roman to integer)-java
直接得到当前的char,将char转为对应的数字,将now与prev对比,如果now大,说明是4或9,result=result+now-2prev;(4=1+5-21)
否则+now,然后prev=now
把switch换为map,map里包含罗马字母的一个字母和两个字母所有可能的值,每次先查是否是两个字母的情况,再确定加多少,最快方法

leetcode-118-杨辉三角(pascl triangle)-java
每一行的首元素和尾元素均为1,并且它们在上一行没有对应的左上方或右上方元素,故我们应该单独处理,对于中间的元素,就只需要获得它的左上方的元素和右上方的元素之和即可。
中间之后,可以取同一行之前的数

leetcode-268-缺失数字(missing number)-java
可以发现,不用遍历数组得到max,数字范围在[0,length]内,直接求出sum,一个个减去,即可得到缺少的数字

leetcode-202-快乐数(happy number)-java
检验循环链表的方法:hashset,快慢指针
注意:如果是循环链表的话,可能快慢指针比hashset更好,如果链表过长,hashset可能会非常大,快慢指针不会出现这种情况。
得到数的平方和:转为string,拆分char后平方和,或者,每次mod10在/10的平方和

检验循环的方法:hashset,是否为4,快慢指针
得到数的平方和:转为string,拆分char后平方和,或者,每次mod10在/10的平方和

leetcode-172-阶乘后的零(factorial trailing zeroes)-java
0=2*5
而阶乘中,有5必有2,所有只要算有几个5就行了
还需要得到每个数分解质因子后5的个数
=n/5+n/25+…

leetcode-171-Excel表列序号(excel sheet column number)-java
每个字母代表的数字是now-‘A’+1
每次就是sum*26+now

leetcode-50-Pow(x, n)-java
1、n可能为负值,此时需要考虑取绝对值
2、由于n为有符号整型变量,范围为-2147483648~2147483647,取最小值时,如果取绝对值会导致溢出,所以先将负数+1,最后多除一次x。
利用二进制方法,将n用二进制展开,例如求25,其中5=101(2)=1∗22+0∗21+1∗20,故25=21∗22+0∗21+1∗20=51∗22∗50∗21∗51∗20
从上述例子可以看出,可以把n写成二进制,对应位为1时,则乘以当前值,否则不乘;
当前值为x的1,2,4,8。。倍,每次temp*temp即可

leetcode-69-x 的平方根(sqrt(t))-java
解法1:
首先先声明,举例,一个数字为100,200,3000,长度为3,4,他们的平方根在10-99之间,即长度为2,可以得到平方根长度为(length+1)/2
所以可以得到一个数字的平方根上下限的100,1000,然后使用二分查找得到对应的平方根。
注意:是平方根的话,是if(x>=midmid&&x<(mid+1)(mid+1)) 在一个区间内
二分查找的话,能够改进的就是初始上下限的问题,设置上限作用较大(位数少了一半),设置下限作用较小,但是也还不错,是优化
解法2:
这个题目的本质是让你求平方根,比如求x^2=t ,我们可以设一个函数f(x)=x^2- t ,令f(x)=0,很明显解x就是t的平方根,在图里表示为与X轴的交点横坐标。而我们要做的就是求出这个交点,手段是取图像上一个初始点(t,f(t)),作它的切线,切线与X轴交点横坐标为X0,接下来我们又作(X0,f(X0))的切线,有没有发现,我们作的切线再逐渐向左偏,切线与X轴的交点也慢慢接近图像与X轴的交点,一直重复以上作切线过程,最后它们会无限逼近,到最后f(Xn)近似等于0(i从0到n),那么我们就可以认为Xn就是要求的平方根。
平方根的具体过程如下:
1、题目要求的是x的平方根,所以t =x,同时我们假设x0开始等于x;
2、如上图所示,过点(x0,f(x0))做曲线的切线 ,切线方程是y1-f( x0 )=f(x0)’ ( x1 - x0 ) - t,令y1=0,解得x1=x0 / 2+t / (2x0)
3、接下来重复2,即过点(x1,f(x1))做曲线的切线,切线方程是y2-f(x1)=f(x1)’(x2-x1) - t ,令y2=0,解得x2=x1 / 2 +t /(2
x1)
接着重复2,一直到 f(xn) 趋向于0,而f(xn)=xn^2-t=0,所以最后近似解就是xn

leetcode-29-两数相除(divide two integers)-java
二进制相关的形式来实现。"<<“和”>>"分别为将数的整体左移和右移,例如a<<1表示将a向左移动一位,即变为原来的二倍。
思路:当被除数大于等于除数时(否则的话就为0了),我们设置两个变量t和p,并分别初始化为除数和1(最小的情况),当被除数大于等于t的二倍时,将t和p同时扩大二倍(左移),并将返回值加上p,除数减去t。和二进制类似,例如29除以8,8扩大二倍,16小于29,再扩大二倍,超过29,于是29减去之前的16,返回值加上2。第二次循环时因为此时的13小于8的二倍,故加上1,整个循环结束,最终结果为2+1=3,很明显符合。此外注意判断结果正负号的正负号时亦或的作用。

leetcode-166-分数到小数(fraction to recurring decimal)-java
分析:这里面需要考虑下面几个问题:
1、如何循环求数?
2、如何判断重复?
3、如何结束循环?
4、会不会溢出?
对于第一个问题:如果直接除数除以被除数,然后去逐位来找,那样的话是非常难以实现的(即使可以实现,那找循环体简直变成了不可能事件)。那换个思路,我们每次都作除,然后取整数部分,然后余数10,继续下去。这样就简单多了,因为取整是非常简单的(强制类型转换即可)。
第二个问题:如何判断重复,对于这种思路而言,当余数在以前的历史中出现过,就可以判断剩下的数据也会不断重复。因此,我们可以存一个hashmap,key就是出现的除数,然后value就是结果数组的index值。只要包含该key时,就可以停止了。
第三个问题:已经回答了,只要包含有key或者除数为0时就可以停止了。
第四个问题:溢出怎么办?对待溢出最简单的解决方案是将其转换为更大的类型。
循环的本质是:例如
a=x
b+y 然后a=y10,然后a=xb+y 下一次出现的y与上一次的y相同。
注意:y不一定只有一位,如果被除数b超过1位,比如17,y可能为15之类的,所以记录下每次的余数y即可。

leetcode-371-两整数之和(sum of two integers)-java

首先我们可以分析人们是如何做十进制的加法的,比如是如何得出5+17=22这个结果的。实际上,我们可以分成三步进行:
1、只做各位相加不进位,此时相加的结果是12(个位数5和7相加不要进位是2,十位数0和1相加结果是1);
2、做进位,5+7中有进位,进位的值是10;第三步把前面两个结果加起来,12+10的结果是22,刚好5+17=22。

3、我们一直在想,求两数之和四则运算都不能用,那还能用什么?对数字做运算,除了四则运算之外,也就只剩下位运算了。位运算是针对二进制的,我们就以二进制再来分析一下前面的三步走策略对二进制是不是也适用。
5的二进制是101,17的二进制是10001。还是试着把计算分成三步:
1、 各位相加但不计进位,得到的结果是10100(最后一位两个数都是1,相加的结果是二进制的10。这一步不计进位,因此结果仍然是0);
2、记下进位。在这个例子中只在最后一位相加时产生一个进位,结果是二进制的10;
3、把前两步的结果相加,得到的结果是10110,转换成十进制正好是22。由此可见三步走的策略对二进制也是适用的。

  接下来我们试着把二进制的加法用位运算来替代。第一步不考虑进位对每一位相加。0加0、1加1的结果都0,0加1、1加0的结果都是1。我们注意到,这和异或的结果是一样的。对异或而言,0和0、1和1异或的结果是0,而0和1、l和0的异或结果是1。接着考虑第二步进位,对0加0、0加1、1加0而言,都不会产生进位,只有1加1时,会向前产生一个进位。此时我们可以想象成是两个数先做位与运算,然后再向左移动一位。只有两个数都是1的时候,位与得到的结果是1,其余都是0。第三步把前两个步骤的结果相加。第三步相加的过程依然是重复前面两步,直到不产生进位为止。

leetcode-169-求众数 (majority element)-java
解法1(成功,27ms,很慢)
用hashmap装入key为数字,value为数字出现的个数,当加入的value大于mid时返回now
时间o(n) 空间o(n)
解法2(别人的)
速度更慢,但很有趣
因为是非空,并且一定有众数,那么把这个数组排序,然后取中间的值,就肯定是众数。
解法3(别人的)
摩尔投票算法
假设有这样一个场景:票选村长,每人可投一票,我们将候选村长从1开始编号,村民们在票上写上候选村长的编号即可完成投票。那么最后统计的票可形成一个整型数组。那么谁是村长呢?票数过半的那个人。
摩尔投票算法可以快速的计算出一个数组中出现次数过半的数即大多数(majority),算法核心思想是同加,异减。我们举个例子。
假设数组是:[1,2,1,1,2,1]。算法步骤如下:
1。当前大多数是1,得分置1
2。与当前大多数不同,得分 - 1,得分为0,当前大多数 = 1
1。与当前大多数不同,得分为0,所以设置当前大多数 1 -> 1,得分置1
1。与当前大多数相同,得分 + 1,得分为2,当前大多数 = 1
2。与当前大多数不同,得分 - 1 ,得分为1,当前大多数 = 1
1。与当前大多数相同,得分 + 1,得分为2,当前大多数 = 1
这意味着1是这个数组中出现次数过半的数。
可以感受得到,算法会保存一个当前大多数,和得分,当遇到一个数不是当前大多数时,得分会减一,当减到0时,大多数会发生改变,并且重置得分为1。

leetcode-621-任务调度器(task scheduler)-java
从举例子中我们可以得出任务调度的规律。
如给定:AAABBCD,n=2。那么我们满足个数最多的任务所需的数量,即可以满足任务间隔要求,即:AXXAXXA;(其中,X表示需要填充任务或者idle的间隔)
如果有两种或两种以上的任务具有相同的最多的任务数,如:AAAABBBBCCDE,n=3。那么我们将具有相同个数的任务A和B视为一个任务对,最终满足要求的分配为:ABXXABXXABXXAB,剩余的任务在不违背要求间隔的情况下穿插进间隔位置即可,空缺位置补idle。
由上面的分析我们可以得到最终需要最少的任务时间:(最多任务数-1)*(n + 1) + (相同最多任务的任务个数)。
有上面的例子来说就是:(num(A)-1) * (3+1) + (2)。
但是有种情况是间隔太少,导致最大的任务执行完后,其他的还没执行,所以要和任务总数,求一个max,因为至少有任务总数秒

leetcode-227-基本计算器 II-java
将表达式(中缀)转化为后缀(即变成逆波兰表达式)
将后缀计算出结果
具体规则为:

1.中缀转后缀:
数字直接输出到后缀表达式
栈为空时,遇到运算符,直接入栈
遇到运算符,弹出所有优先级大于或等于该运算符的栈顶元素,并将该运算符入栈(+ - 大, * / 小)
将栈中元素依次出栈
例如:表达式:3+2 * 2
遇到3,直接输出到后缀表达式中,栈中元素为空,结果为: 栈: 空; 后缀表达式:3
遇到符号“+”,入栈,结果为: 栈:+ ; 后缀表达式:3
遇到2,直接输出,结果为: 栈:+; 后缀表达式: 3 2
遇到乘号*,入栈,结果为: 栈: * + ;后缀表达式:3 2
遇到2,直接输出,结果为: 栈: * + ;后缀表达式:3 2 2
最后,将元素出栈:结果为:后缀表达式:3 2 2 * +

2.计算后缀:
遇到数字,入栈
遇到运算符,弹出栈顶两个元素,做运算,并将结果入栈
重复上述步骤,直到表达式最右端
例如上述得到的后缀表达式为 3 2 2 * +
3 2 2 都是数字,入栈,结果为:栈:2 2 3
遇到* 号, 2 2 出栈,并计算,2*2 = 4, 4入栈,结果为:栈:4 3 ,表达式还剩一个加号
遇到+ 号,栈顶两个元素出栈并运算,4 3 做加法,4+3 =7
后缀表达式空了,计算完毕,输出结果:7

你可能感兴趣的:(算法-数学,leetcode,leetcode总结)