数字的位操作——7、9、479、564、231、342

7. 整数反转(中等)

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

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

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

提示:

  • -231 <= x <= 231 - 1

解法一、字符串操作,考虑多种情况模拟 (16mins)

复杂但不烧脑。。参考了之前一道题的边界讨论方式(即这里的bound),正负数需要分开辨别。用了StringBuffer的reverse API

使用负号记录,转换时不考虑负号,避免长度出问题(而且翻转后负号会去后面)。长度>10,越界。长度<10,三目讨论正负。长度等于10,分正负号讨论是否越界。

class Solution {
    public static int reverse(int x) {
        boolean negative = false;
        if(x < 0){
            negative = true;
            x = Math.abs(x);
        }
        StringBuffer sb = new StringBuffer(String.valueOf(x)).reverse();
        int bound = Integer.MAX_VALUE / 10;//原十位 这里九位
        if(sb.length() > 10){
            return 0;
        }else if(sb.length() <= 9){
            return negative ? -Integer.parseInt(sb.toString()):Integer.parseInt(sb.toString());
        }else{
            if(Integer.parseInt(sb.toString().substring(0,9)) > bound){
                return 0;
            }else if(Integer.parseInt(sb.toString().substring(0,10)) < bound){
                return negative ? -Integer.parseInt(sb.toString()):Integer.parseInt(sb.toString());
            }else{
                    if((negative && sb.toString().charAt(9) - '8' > 0 )|| (!negative && sb.toString().charAt(9) - '7' > 0 )){
                        return 0;
                    }else{
                        return negative ? -Integer.parseInt(sb.toString()):Integer.parseInt(sb.toString());
                }
            }
        }
    }
}

解法二、循环取数

这里观看评论区,有以下收获:

  • 由于原始int数据,例如对于2147483647(最大情况),原数据不溢出、翻转后可以溢出的,一定是类似22*******1/2的情况。总之,尾数一定是1或者2,就不必再考虑tmp>7和<-8,因为数据限制。
  • 因为这里是手动转int,不使用Integer.valueOf api的话,就可以规避报错。所以,比起转换途中考虑是否溢出,不如直接转换完毕之后讨论是否溢出,是一个非常灵巧的逆向思维。而转换的方式就是last == res / 10(last是上一步的结果,res是这一步的结果),如果溢出,显然就不相等了。也就是说,考虑溢出确实是重要的,但利用溢出也很重要。
  • 模不能是负数,但负数可以取模。余数符号与被模数相同。
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;
    }
}			

作者:王尼玛
链接:https://leetcode.cn/problems/reverse-integer/solutions/211865/tu-jie-7-zheng-shu-fan-zhuan-by-wang_ni_ma/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 
9. 回文数(简单)

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数

是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121
输出:true

示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

提示:

  • -231 <= x <= 231 - 1

进阶:你能不将整数转为字符串来解决这个问题吗?

解法一  翻转再比对(3mins)

先转换再考虑相等。如果原数不溢出,转换数肯定也不溢出。感觉数字比字符串的回文好算的缘故是可以直接比对,不好算的缘故是无法精确且迅速地取下标

class Solution {
    public static boolean isPalindrome(int x) {
        if(x < 0)return false;
        int t = x;
        int res = 0;
        while(x!=0){
            int temp = x %10;
            res = res * 10 + temp;
            x /=10;
        }
        return t == res ? true:false;
    }
}

 

解法二 解法一优化

本质上和解法一是一样的,但是①不需要声明额外变量②return里用||和/10来去除奇数位时翻转数中位的思想很天才。如,原数字是12321,处理后变成x=12 翻转数 =123 这个3不需要辨识,它总与自身相等。

while循环的条件:处理一半(即翻转一半)就足够考虑是否相等了。

class Solution {
    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;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/palindrome-number/solutions/281686/hui-wen-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 解法三、评论区的拉马努金解法

默默地服了。。

class Solution {
    public boolean isPalindrome(int x) { 
        if(x==1122||x==123123||x==1000021||x==21120||x<0)return false;
        if(x<10&&x>=0||x%11==0||x==313||x==101||x==88888||x==2222222)return true;     
        else return false;          
    } 
}

479. 最大回文数乘积(困难)

给定一个整数 n ,返回 可表示为两个 n 位整数乘积的 最大回文整数 。因为答案可能非常大,所以返回它对 1337 取余 。

示例 1:

输入:n = 2
输出:987
解释:99 x 91 = 9009, 9009 % 1337 = 987

示例 2:

输入:n = 1
输出:9

提示:

  • 1 <= n <= 8

解法一、暴力枚举

没感觉到任何这道题配是困难的地方。证明也很粗糙。。直奔题解了。原思路是二重循环转字符串开乘,感觉很艰涩,不过这个字符串乘法模板还挺有意思的。总感觉和之前做过的一道题有点像。。

字符串乘法模板
    public String multiplyStrings(String num1, String num2) {
        int m = num1.length(), n = num2.length();
        int[] pos = new int[m + n];

        for (int i = m - 1; i >= 0; i--) {
            for (int j = n - 1; j >= 0; j--) {
                int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
                int sum = mul + pos[i + j + 1];

                pos[i + j] += sum / 10;
                pos[i + j + 1] = sum % 10;
            }
        }

        StringBuilder sb = new StringBuilder();
        for (int p : pos) {
            if (!(sb.length() == 0 && p == 0)) {
                sb.append(p);
            }
        }

        return sb.length() == 0 ? "0" : sb.toString();
    }
题解

其实就是对于n位数相乘,上限2n位,往下找回文串。不用确认是不是回文,直接确定左面造右面。 甚至还用了long,不讲武德。。83ms,居然没有超时

class Solution {
    public int largestPalindrome(int n) {
        if (n == 1) return 9;
        int max = (int) Math.pow(10, n) - 1;
        for (int i = max; i >= 0; i--) {
            long num = i, t = i;
            while (t != 0) {
                num = num * 10 + (t % 10);
                t /= 10;
            }
            for (long j = max; j * j >= num; j--) {
                if (num % j == 0) return (int)(num % 1337);
            }
        }
        return -1;
    }
}

作者:宫水三叶
链接:https://leetcode.cn/problems/largest-palindrome-product/solutions/1424568/by-ac_oier-t8j7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解法二、你说得对,但我打表

class Solution {
    static int[] ans = new int[]{9,987,123,597,677,1218,877,475};
    public int largestPalindrome(int n) {       
        return ans[n - 1];
    }
}

564. 寻找最近的回文数(困难)

给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。

“最近的”定义为两个整数差的绝对值最小。

示例 1:

输入: n = "123"
输出: "121"

示例 2:

输入: n = "1"
输出: "0"
解释: 0 和 2是最近的回文,但我们返回最小的,也就是 0。

提示:

  • 1 <= n.length <= 18
  • n 只由数字组成
  • n 不含前导 0
  • n 代表在 [1, 1018 - 1] 范围内的整数

解法一、暴力枚举

假如例子是12345,那么取出123,造一个100001,造一个9999,造一个12221,造一个12321,造一个12421,比较五个里哪个差值最小。

是long,它用了long魔法jpg

看评论区说是字节三面。感觉这种形式暴力出来的题真的很有用吗。。甚至写完都没感觉到有特别能讲的地方

倒是明显感觉到边界处理进步了很多,造轮子速度也快了

class Solution {
    public static String nearestPalindromic(String n) {
        int len = n.length();
        long cur = Long.parseLong(n);
        Set<Long> res = new HashSet<>();
        res.add((long)Math.pow(10,len) +1);
        res.add((long)Math.pow(10,len-1) -1);
        long t = Long.parseLong(n.substring(0,(len+1)/2));
        for(long i = t-1;i <= t+1;i++){
            long temp = getNum(i,len % 2 == 0);
            if(temp != cur){
                res.add(temp);
            }
        }
        long r = -1;
        long min = Long.MAX_VALUE;
        for(long num : res){
            if(r == -1)r = num;
            if(Math.abs(num - cur) < min){
                min = Math.abs(num - cur);
                r = num;
            }else if(Math.abs(num - cur) == min && num < r){
                r = num;
            }
        }
        return String.valueOf(r);
    }
    public static long getNum(long k,boolean isEven){
        long t = k;
        //123456
        //122 t = 122

        if(!isEven) {//偶数
            t /= 10;
        }
        while (t != 0) {
            k = k * 10 + t % 10;
            t /= 10;
        }
        return k;
    }
}

 

 
231. 2 的幂(简单)

相关标签

相关企业

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

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

示例 1:

输入:n = 1
输出:true
解释:20 = 1

示例 2:

输入:n = 16
输出:true
解释:24 = 16

示例 3:

输入:n = 3
输出:false

提示:

  • -231 <= n <= 231 - 1

进阶:你能够不使用循环/递归解决此问题吗?

 

解法一、暴力

试着用2一路乘了,成功超时。(。。。

解法二、换底公式 

一个数字时是以e为底。如果n是2的幂,那么返回应该是个整数

class Solution {
    public boolean isPowerOfTwo(int n) {
        if (n <= 0) return false;
        // 换底公式
        double log_2_n = Math.log(n) / Math.log(2);
        return log_2_n == (int) log_2_n;
    }
}

解法三、和最大比较

2的幂即约数只有2,不妨和2^30取一下模。

class Solution {
    static final int BIG = 1 << 30;

    public boolean isPowerOfTwo(int n) {
        return n > 0 && BIG % n == 0;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/power-of-two/solutions/796201/2de-mi-by-leetcode-solution-rny3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解法四、位运算

两种解法放一起了。n&(n-1),如果是2的幂,则二进制是10···00,假如是1000,n-1则是0111,按位与可以移除。 取负同理

class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && (n & (n - 1)) == 0;
    }
}
class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && (n & -n) == n;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/power-of-two/solutions/796201/2de-mi-by-leetcode-solution-rny3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

342. 4的幂

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

整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x

示例 1:

输入:n = 16
输出:true

示例 2:

输入:n = 5
输出:false

示例 3:

输入:n = 1
输出:true

提示:

  • -231 <= n <= 231 - 1

进阶:你能不使用循环或者递归来完成本题吗?

 

解法一、换底 

class Solution {
    public boolean isPowerOfFour(int n) {
        if(n <=0)return false;
        double t = Math.log(n)/Math.log(4);
        return t == (int)t ? true:false;
    }
}

 

 解法二、位运算+长度确认

比如2是10 4的二进制是100,总之1/4/16转二进制都是奇数长度

class Solution {
    public static boolean isPowerOfFour(int n) {
        String a = Integer.toBinaryString(n);
        return n > 0 && (n & (n - 1)) == 0 && a.length() % 2 == 1 ? true:false;
    }
}

 

 用十六进制的aaaaaa作为标识(这个转换为二进制的形式是1010,偶数位是1,与可以把奇数位消掉)

class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && (n & 0xaaaaaaaa) == 0;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/power-of-four/solutions/798268/4de-mi-by-leetcode-solution-b3ya/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

取模,4%3 = 1,2%3 = 2。。这个好厉害啊( 

class Solution {
public:
    bool isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/power-of-four/solutions/798268/4de-mi-by-leetcode-solution-b3ya/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 


碎碎念

  • HashSet看起来还挺好用的,第一次用到,能够用foreach也挺开心,喜欢
  • 虽然是简单,但是没想到位运算的话就会很复杂,空套循环。。是真的需要提高对二进制数字的敏感度了
  • 被马拉车+BF+KMP整自闭了一段时间,昨天休息了一天,今天一打开三简一中两困难(耗时三小时五分),也是又感觉有点命运多舛了 
  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值