力扣刷题序列 - 数学

数学的位操作

1:整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。
在这里插入图片描述

题解: 用取模运算向拼接处一个数字了,也就能达到 反转 的效果。 循环的判断条件是x>0但这样不对,因为忽略了 负数 循环的判断条件应该是while(x!=0),无论正数还是负数,按照上面不断的/10这样的操作,最后都会变成0,所以判断终止条件就是!=0
有了取模和除法操作,对于像12300这样的数字,也可以完美的解决掉了。

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。
也就是说我们不能用long存储最终结果,而且有些数字可能是合法范围内的数字,但是反转过来就超过范围了。假设有1147483649这个数字,它是小于最大的32位整数2147483647的,但是将这个数字反转过来后就变成了9463847411,这就比最大的32位整数还要大了,这样的数字是没法存到int里面的,所以肯定要返回0(溢出了)。

class Solution {
     public int reverse(int x) {
        int res = 0;
        while(x!=0) {
            //每次取末尾数字
            int tmp = x%10;
            //判断是否 大于 最大32位整数
            if (res>214748364 || (res==214748364 && tmp>7)) {
                return 0;
            }
            //判断是否 小于 最小32位整数
            if (res<-214748364 || (res==-214748364 && tmp<-8)) {
                return 0;
            }
            res = res*10 + tmp;
            x /= 10;
        }
        return res;
    }
}

2.回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。

 public static boolean isPalindrome(int x) {
        int y=0;
        int x1=x;
        while (x>0){
            y =y*10+(x%10);
            x/=10;
        }
        if (y==x1)return true;
        return false;
    }

力扣官方解法

 public boolean isPalindrome(int x) {
        // 特殊情况:
        // 如上所述,当 x < 0 时,x 不是回文数。
        // 同样地,如果数字的最后一位是 0,为了使该数字为回文,
        // 则其第一位数字也应该是 0
        // 只有 0 满足这一属性
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

        int revertedNumber = 0;
        while (x > revertedNumber) {
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }

        // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
        // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
        // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
        return x == revertedNumber || x == revertedNumber / 10;
    }


479. 最大回文数乘积

在这里插入图片描述

class Solution {
    public int largestPalindrome(int n) {
        if (n == 1) {
            return 9;
        }
        int upper = (int) Math.pow(10, n) - 1;
        int ans = 0;
        for (int left = upper; ans == 0; --left) { // 枚举回文数的左半部分
            long p = left;
            for (int x = left; x > 0; x /= 10) {
                p = p * 10 + x % 10; // 翻转左半部分到其自身末尾,构造回文数 p
            }
            for (long x = upper; x * x >= p; --x) {
                if (p % x == 0) { // x 是 p 的因子
                    ans = (int) (p % 1337);
                    break;
                }
            }
        }
        return ans;
    }
}

第二种解法- 直接打表

打表常见的用法有如下几种:

1、在程序中一次性计算出所有需要用到的结果,之后的查询直接取这些结果

这个是最常用到的用法,例如在一个需要查询大量Fibonacci数F(n)的问题中,显然每次从头开始计算是非常耗时的,对Q次查询会产生O(nQ)的时间复杂度;而如果进行预处理,即把所有Fibonacci数预先计算并存在数组中,那么每次查询就只需O(1)的时间复杂度,对Q次查询就值需要O(n+Q)的时间复杂度(其中O(n)是预处理的时间)。

2、在程序B中分一次或多次计算出所有需要用到的结果,手工把结果写在程序A的数组中,然后在程序A中就可以直接使用这些结果

这种用法一般是当程序的一部分过程小号的时间过多,或是没有想到好的算法,因此在另一个程序中使用暴力算法算出结果,这样就能直接在源程序中使用这些结果。例如对n皇后问题来说,如果使用的算法不够好,就容易超时,而可以在本地用程序计算付出对所有n来说n皇后问题的方案数,然后把算出的结果直接卸载数组中,就可以根据题目输入的n来直接输出结果。

3、对一些感觉不会做的题目,先用暴力程序计算小范围数据的结果,然后找规律,或许就能发现一些“蛛丝马迹”

{9,987,123,597,677,1218,877,475}

231.2 的幂

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true;否则,返回 false 。

 public boolean isPowerOfTwo(int n) {
        if(n == 0)return false;
        if(n < 0)return false;
        return ( n & (n -1)) == 0;
    }

342.4的幂

给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。

public boolean isPowerOfFour(int n) {
        return n>0&&( n & (n -1)) == 0 && (n & 0x55555555) != 0;
    }

326.3 的幂

给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。

 public boolean isPowerOfThree(int n) {
         while (n != 0 && n % 3 == 0) {
            n /= 3;
        }
        return n == 1;
    }

504 . 7进制

给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。

public String convertToBase7(int num) {
        //给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。
        //用除留取余数法
        if (num == 0){
            return "0";
        }
        int n =num;
        Stack<Integer> stack = new Stack<>();
        while (n != 0){
            stack.add(Math.abs(n%7));
            n=n/7;
        }
        StringBuilder stringBuilder = new StringBuilder();
        while (!stack.isEmpty()){
            stringBuilder.append(stack.pop());
        }
        if (num < 0)return "-"+stringBuilder.toString();
        return stringBuilder.toString();
    }

263 . 丑数

丑数 就是只包含质因数 2、3 和 5 的正整数。

给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。

 public boolean isUgly(int n) {
        //丑数 就是只包含质因数 2、3 和 5 的正整数
        if (n <= 0) {
            return false;
        }
        int[] factors = {2, 3, 5};
        for (int factor : factors) {
            while (n % factor == 0) {
                n /= factor;
            }
        }
        return n == 1;
    }

190 .颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

将 n 视作一个长为 32 的二进制串,从低位往高位枚举 n 的每一位,将其倒序添加到翻转结果 rev 中。

代码实现中,每枚举一位就将n 右移一位,这样当前 n 的最低位就是我们要枚举的比特位。当 n 为 0 时即可结束循环。

需要注意的是,在某些语言如 Java中,没有无符号整数类型,因此对 n 的右移操作应使用逻辑右移。

 public int reverseBits(int n) {
        //颠倒给定的 32 位无符号整数的二进制位。
        int rev = 0;
        for (int i = 0; i < 32 && n != 0; ++i) {
            rev |= (n & 1) << (31 - i);
            n >>>= 1;
        }
        return rev;
    }

191 . 位1的个数

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

 public int hammingWeight(int n) {
        // 二进制1的个数
        int ret = 0;
        while (n != 0){
            n=n&n-1;
            ret++;
        }
        return ret;
    }

476 .补数

对整数的二进制表示取反(0 变 1 ,1 变 0)后,再转换为十进制表示,可以得到这个整数的补数。
解法: 找到最高位的1,然后按位取反就行

 public int findComplement(int num) {
        int s = -1;
        // 找到最高位的1
        for (int i = 31; i >= 0; i--) {
            if (((num >> i) & 1) != 0) {
                s = i;
                break;
            }
        }
        // 然后按位取反
        int ans = 0;
        for (int i = 0; i < s; i++) {
            if (((num >> i) & 1) == 0) ans |= (1 << i);
        }
        return ans;
    }

461 .汉明距离

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

,记 s=x⊕y我们可以不断地检查 s 的最低位,如果最低位为 1,那么令计数器加一,然后我们令 s 整体右移一位,这样 s 的最低位将被舍去,原本的次低位就变成了新的最低位。我们重复这个过程直到 s=0为止。这样计数器中就累计了 s 的二进制表示中 1 的数量。

public int hammingDistance(int x, int y) {
        int s = x ^ y, ret = 0;
        while (s != 0) {
            ret += s & 1;
            s >>= 1;
        }
        return ret;
    }

693.交替位二进制数

给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同
解法: 我们用对 2 取模再除以 2 的方法,依次求出输入的二进制表示的每一位,并与前一位进行比较。如果相同,则不符合条件;如果每次比较都不相同,则符合条件

public static boolean hasAlternatingBits(int n) {
        int prev = 2;
        while (n != 0) {
            int cur = n % 2;
            if (cur == prev) {
                return false;
            }
            prev = cur;
            n /= 2;
        }
        return true;
    }

172.阶乘后的零

给定一个整数 n ,返回 n! 结果中尾随零的数量。
解法: 判断阶层中5的个数

public int trailingZeroes(int n) {
        int ans = 0;
        for (int i = 5; i <= n; i += 5) {
            for (int x = i; x % 5 == 0; x /= 5) {
                ++ans;
            }
        }
        return ans;
    }

258.各位相加

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

public int addDigits(int num) {
        while (num >= 10) {
            int sum = 0;
            while (num > 0) {
                sum += num % 10;
                num /= 10;
            }
            num = sum;
        }
        return num;
    }

405.数字转换为十六进制数

对于负整数,我们通常使用 补码运算 方法。

 public String toHex(int _num) {
        if (_num == 0) return "0";
        long num = _num;
        StringBuilder sb = new StringBuilder();
        if(num < 0) num = (long)(Math.pow(2, 32) + num);
        while (num != 0) {
            long u = num % 16;
            char c = (char)(u + '0');
            if (u >= 10) c = (char)(u - 10 + 'a');
            sb.append(c);
            num /= 16;
        }
        return sb.reverse().toString();
    }

171.Excel 表列序号

在这里插入图片描述

  public String toHex(int _num) {
        if (_num == 0) return "0";
        long num = _num;
        StringBuilder sb = new StringBuilder();
        if(num < 0) num = (long)(Math.pow(2, 32) + num);
        while (num != 0) {
            long u = num % 16;
            char c = (char)(u + '0');
            if (u >= 10) c = (char)(u - 10 + 'a');
            sb.append(c);
            num /= 16;
        }
        return sb.reverse().toString();
    }

168. Excel表列名称

在这里插入图片描述

public String convertToTitle(int columnNumber) {
        StringBuffer sb = new StringBuffer();
        while (columnNumber > 0) {
            int a0 = (columnNumber - 1) % 26 + 1;
            sb.append((char)(a0 - 1 + 'A'));
            columnNumber = (columnNumber - a0) / 26;
        }
        return sb.reverse().toString();
    }

670. 最大交换

给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

核心思路:将最靠后的最大的数,与最靠前的小于它的数交换(若存在),

public int maximumSwap(int num) {
        char[] ch = String.valueOf(num).toCharArray();
        int len = ch.length;
        int maxIndex = len - 1;//定义候选数的位置
        int left = 0,right = 0;//定义两个需要交换的数的位置
        for (int i = len - 1;i >= 0;i--) {
            if (ch[i] > ch[maxIndex]) maxIndex = i;//若候选数前出现了比它大的数,那么更新候选数。
            else if (ch[i] < ch[maxIndex]) {
                left = i;
                right = maxIndex;//只有当候选数前存在比它小的数,才需要交换位置
            }
        }
        swap(ch,left,right);
        return Integer.parseInt(new String(ch));
    }
    public void swap(char[] arr,int i,int j) {
        char temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

233.数字 1 的个数

给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
在这里插入图片描述

class Solution {
     public int countDigitOne(int n) {
        int digit = 1, res = 0;
        int high = n / 10, cur = n % 10, low = 0;
        while(high != 0 || cur != 0) {
            if(cur == 0) res += high * digit;
            else if(cur == 1) res += high * digit + low + 1;
            else res += (high + 1) * digit;
            low += cur * digit;
            cur = high % 10;
            high /= 10;
            digit *= 10;
        }
        return res;
    }
}

357.统计各位数字都不同的数字个数

n=0,数字有{0}1个。
n=1,数字有{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}10个。
n=2,数字包括两部分之和,一部分为n=1的所有10个答案,另一部分为长度为2的新增数字。长度为2的新增数字可以在n=1的所有9个数字基础上进行拼接(0不能算)。例如:
从n=1的数字列表{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}中随便取出一个除0以外的数字(因为0不能作为起始数字!),我们取2好了。通过在2的尾巴处拼接一位数字可以得到新的合法数字有:
{20, 21,23,24,25,26,27,28,29},
可以看到,除了不能在尾巴处拼接一个2(两个连续的2就非法了!),0-9种一共有9个数字可以拿拼接在尾巴处。新增答案为9个。同理,对于n=1数字列表{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}中的其他任意非0数也可以进行拼接操作,一共可以新增99个答案。
最终,n=2的合法数字,n=1时的答案 + 长度为2的数字个数(9
9个)= 10 + 81 = 91。
n=3时同理,只不过此时可以用拼接的数字减少为了8个,此时答案为10 + 9 * 9 + 9 * 9 * 8 = 739。
通过归纳不难得到,假设 dp[i] 即 n = i时的答案,则动态转移方程为:
dp[i] = dp[i-1] + (dp[i-1] - dp[i-2])*(10-(i-1))

public int countNumbersWithUniqueDigits(int n) {
        if (n == 0) {
            return 1;
        }
        if (n == 1) {
            return 10;
        }
        int res = 10, cur = 9;
        for (int i = 0; i < n - 1; i++) {
            cur *= 9 - i;
            res += cur;
        }
        return res;
    }

简单数学题

492.构造矩形

在这里插入图片描述

  public  int[] constructRectangle(int area) {
        if (area == 1 || area == 0)return new int[]{area,area}; 
        int[] arr = new int[2];
         
        int dif =Integer.MAX_VALUE ; // 记录差值, 差值最小的就是最好的
        for (int i = area/2; i >=1 ; i--) {
            if (area % i == 0 && Math.abs(i-(area/i)) < dif){
                 arr[0] = i > area/i?i:area/i;
                arr[1] =i > area/i?area/i:i;
                dif = i-(area/i);
            }
        }
        return arr;
    }

29.两数相除

507完美数

对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。

给定一个 整数 n, 如果是完美数,返回 true;否则返回 false。

 public boolean checkPerfectNumber(int num) {
           if (num <= 1)return false;//考虑边界
        int isNum =0;
        for (int i = num/2; i > 1 ; i--) {
            if (num % i == 0){
                isNum+=i;
            }
        }
        return isNum+1 == num;
    }

快速幂

50 Pow(x, n)

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。

 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;
    }

372超级次方

在这里插入图片描述

  static final int MOD = 1337;

    public int superPow(int a, int[] b) {
        int ans = 1;
        for (int i = b.length - 1; i >= 0; --i) {
            ans = (int) ((long) ans * pow(a, b[i]) % MOD);
            a = pow(a, 10);
        }
        return ans;
    }

    public int pow(int x, int n) {
        int res = 1;
        while (n != 0) {
            if (n % 2 != 0) {
                res = (int) ((long) res * x % MOD);
            }
            x = (int) ((long) x * x % MOD);
            n /= 2;
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值