简单数学题——492、29、507 快速幂——50、372

 简单数学题

492. 构造矩形(简单)

作为一位web开发者, 懂得怎样去规划一个页面的尺寸是很重要的。 所以,现给定一个具体的矩形页面面积,你的任务是设计一个长度为 L 和宽度为 W 且满足以下要求的矩形的页面。要求:

  1. 你设计的矩形页面必须等于给定的目标面积。
  2. 宽度 W 不应大于长度 L ,换言之,要求 L >= W
  3. 长度 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值