简单数学题
492. 构造矩形(简单)
作为一位web开发者, 懂得怎样去规划一个页面的尺寸是很重要的。 所以,现给定一个具体的矩形页面面积,你的任务是设计一个长度为 L 和宽度为 W 且满足以下要求的矩形的页面。要求:
- 你设计的矩形页面必须等于给定的目标面积。
- 宽度
W
不应大于长度L
,换言之,要求L >= W
。- 长度
L
和宽度W
之间的差距应当尽可能小。返回一个 数组
[L, W]
,其中L
和W
是你按照顺序设计的网页的长度和宽度。
示例1:
输入: 4 输出: [2, 2] 解释: 目标面积是 4, 所有可能的构造方案有 [1,4], [2,2], [4,1]。 但是根据要求2,[1,4] 不符合要求; 根据要求3,[2,2] 比 [4,1] 更能符合要求. 所以输出长度 L 为 2, 宽度 W 为 2。示例 2:
输入: area = 37 输出: [37,1]示例 3:
输入: area = 122122 输出: [427,286]提示:
1 <= area <= 10^7
解法一、开方遍历
取p=area的开方,从p往1遍历(确认是最均衡的情况),如果i*(area/i)==area(也就是说area/i是int整型)则break。满足了均衡和大数在前的条件
class Solution {
public static int[] constructRectangle(int area) {
int p = (int)Math.sqrt(area);
int[] res = new int[2];
for(int i = p;i >0;i--){
if(i * (area / i) == area){
res[1] = i;
res[0] = area/i;
break;
}
}
return res;
}
}
29. 两数相除(中等)
给你两个整数,被除数
dividend
和除数divisor
。将两数相除,要求 不使用 乘法、除法和取余运算。整数除法应该向零截断,也就是截去(
truncate
)其小数部分。例如,8.345
将被截断为8
,-2.7335
将被截断至-2
。返回被除数
dividend
除以除数divisor
得到的 商 。注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是
[−231, 231 − 1]
。本题中,如果商 严格大于231 − 1
,则返回231 − 1
;如果商 严格小于-231
,则返回-231
。示例 1:
输入: dividend = 10, divisor = 3 输出: 3 解释: 10/3 = 3.33333.. ,向零截断后得到 3 。示例 2:
输入: dividend = 7, divisor = -3 输出: -2 解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。提示:
-2^31 <= dividend, divisor <= 2^31 - 1
divisor != 0
解法一、相加遍历
缝缝补补半天最后超时,捏马
class Solution {
public int divide(int dividend, int divisor) {
if(dividend == 0)return 0;
if(dividend == divisor)return 1;
if(dividend == -divisor)return -1;
int sum = 0,res = 0;
boolean f = false;
if((dividend > 0 && divisor < 0) ||(dividend < 0 && divisor > 0)){
f = true;
}
if(dividend!=-2147483648){
dividend = dividend > 0 ? dividend : -dividend;
divisor = divisor > 0 ? divisor : -divisor;
while(sum <= dividend){
sum += divisor;
res++;
}
}else{
if(divisor > 0){
while(sum >= dividend){
sum -= divisor;
res++;
}
}else{
while(sum >= dividend){
sum += divisor;
res++;
}
}
}
return f ? -(--res):--res;
}
}
解法二、优化
正数可能会溢出,所以开场两个判断,记录符号的同时全部转为负数。
n:记录2的幂。如果被除数右移n位之后比除数大(如,-13/ -4 右移2位后是-4,但它只能减以-4 * 2^1,是负数比负数的向下取整问题。compare是比实际上精度的小的,为了确保可以,需要让一位。如果是-16/-4,把n-1改成n也可以通过。)
public int divide(int dividend, int divisor) {
boolean symbol = true;
if (dividend > 0) {
dividend = -dividend;
symbol = false;
}
if (divisor > 0) {
divisor = -divisor;
symbol = !symbol;
}
int result = 0;
while (dividend <= divisor) {
int n = 1;
while (true) {
int compare = dividend >> n;
if (compare >= divisor) {
result -= (int) Math.pow(2, n - 1);
dividend = dividend - (divisor << (n - 1));
break;
}
n++;
}
}
return symbol ? (result == Integer.MIN_VALUE ? Integer.MAX_VALUE : -result) : result;
}
507. 完美数(简单)
对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。
给定一个 整数
n
, 如果是完美数,返回true
;否则返回false
。示例 1:
输入:num = 28 输出:true 解释:28 = 1 + 2 + 4 + 7 + 14 1, 2, 4, 7, 和 14 是 28 的所有正因子。示例 2:
输入:num = 7 输出:false提示:
1 <= num <= 10^8
解法一、遍历枚举
因为不包括它自身,而1一定是正因子,所以直接从sum = 1开始,遍历i∈[2,√num]。不是平方数的情况下都加一遍,是平方数的情况下只加一遍。这里的判断方式也参考了492
class Solution {
public static boolean checkPerfectNumber(int num) {
if(num == 1)return false;
int sum = 1,k = (int)Math.sqrt(num);
for(int i = 2;i <= k;i++){
if(i * (num / i) == num){
sum += i == num/i ? i : i+num/i;
}
}
return sum == num ? true:false;
}
}
解法二、数论打表
根据欧几里得-欧拉定理,每个偶完全数都可以写成
2^(p−1) (2^p −1)的形式,其中 p 为素数且 2^(p−1) 为素数。
由于目前奇完全数还未被发现,因此题目范围 [1,10^8] 内的完全数都可以写成上述形式。
这一共有如下 5 个:
6,28,496,8128,33550336
作者:力扣官方题解
链接:https://leetcode.cn/problems/perfect-number/solutions/1179051/wan-mei-shu-by-leetcode-solution-d5pw/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public boolean checkPerfectNumber(int num) {
return num == 6 || num == 28 || num == 496 || num == 8128 || num == 33550336;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/perfect-number/solutions/1179051/wan-mei-shu-by-leetcode-solution-d5pw/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
快速幂
50. Pow(x, n)(中等)
实现 pow(x, n) ,即计算
x
的整数n
次幂函数(即,xn
)。示例 1:
输入:x = 2.00000, n = 10 输出:1024.00000示例 2:
输入:x = 2.10000, n = 3 输出:9.26100示例 3:
输入:x = 2.00000, n = -2 输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25提示:
-100.0 < x < 100.0
-2^31 <= n <= 2^31-1
n
是一个整数- 要么
x
不为零,要么n > 0
。-10^4 <= xn <= 10^4
解法一、分治递归
对于奇数,是y*y*x,对于偶数,是y*y。
class Solution {
public double myPow(double x, int n) {
long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
public double quickMul(double x, long N) {
if (N == 0) {
return 1.0;
}
double y = quickMul(x, N / 2);
return N % 2 == 0 ? y * y : y * y * x;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/powx-n/solutions/238559/powx-n-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法二、迭代
假设n=77 = 1+4+8+64,正好是1001101,77的二进制。拆分一下,答案就是x^1*x^4*x^8*x^64。
class Solution {
public double myPow(double x, int n) {
long N = n;
return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
}
public double quickMul(double x, long N) {
double ans = 1.0;
// 贡献的初始值为 x
double x_contribute = x;
// 在对 N 进行二进制拆分的同时计算答案
while (N > 0) {
if (N % 2 == 1) {
// 如果 N 二进制表示的最低位为 1,那么需要计入贡献
ans *= x_contribute;
}
// 将贡献不断地平方
x_contribute *= x_contribute;
// 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
N /= 2;
}
return ans;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/powx-n/solutions/238559/powx-n-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三、API
java里是Math.pow(x,n)
class Solution {
public:
double myPow(double x, int n) {
return pow(x,n);
}
};
372. 超级次方(中等)
题解见下~用了递归
. - 力扣(LeetCode)
superPow:主体
dfs:按个遍历,拆解,如将2345拆成234*10 + 5
speed:快速幂(具体原理可以见50)
class Solution {
int mod = 1337;
public int superPow(int a, int[] b) {
return dfs(a,b,b.length-1);
}
private int dfs(int a,int[] b,int u){
if(u == -1)return 1;
return speed(dfs(a,b,u-1),10) * speed(a,b[u]) % mod;
}
private int speed(int a,int b){
int sum = 1;
a%=mod;
while(b > 0){
if(b % 2 == 1)sum = sum * a % mod;
a = a * a %mod;
b >>= 1;
}
return sum;
}
}
碎碎念
- 快速幂和快速和其实还是不太一样,前者是二进制位运算,后者是根据2的幂作比较,需要考虑非整除的舍入。被除数/2,除数*2^(n-1),还是感觉是很精妙的算法
- 492和507都用到了i*(num/i)==num来确认约数。29学快速和,50学快速幂原理,372其实学的是各式拆解。也可以用到欧拉公式,今天没有心力再次学习了orz