整数反转相关题型

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 整数反转相关题型

7. 整数反转

本题来自 LeetCode:7. 整数反转[1]

题目描述

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例  1:


输入: 123
输出: 321

示例 2:


输入: -123
输出: -321

示例 3:


输入: 120
输出: 21

注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

题目分析

本题题意为反转整数的数字,主要需要考虑反转后,是否越界。
对于整数 num = i * 10 + j是否越界,即无法通过 [−2^31, 2^31 − 1]正确表示。主要分两种情况分析。

  • `num`为正整数,那么满足以下条件,即表示越界:
  • `i Integer.MAX_VALUE / 10`;
  • `i == Integer.MAX_VALUE / 10 && j Integer.MAX_VALUE % 10`;
  • `num`为负整数,那么满足以下条件,即表示越界:
  • `i Integer.MIN_VALUE / 10`;
  • `i == Integer.MIN_VALUE / 10 && j Integer.MIN_VALUE % 10`;
  • 题目解答

    
    class Solution {
    
        // 最大值除10的余数
        private static final int maxValueMod = Integer.MAX_VALUE % 10;
        // 最小值除10的余数
        private static final int minValueMod = Integer.MIN_VALUE % 10;
        // 最大值除10的结果值
        private static final int maxValue_10 = Integer.MAX_VALUE / 10;
        // 最小值除10的结果值
        private static final int minValue_10 = Integer.MIN_VALUE / 10;
    
        public int reverse(int x) {
            // 是否为正数
            boolean positive = x  0;
    
            int reverse = 0;
            while(x != 0) {
                int digit = x % 10;
                x /= 10;
                // 判读是否越界
                if(positive) {
                    // 判断正数是否越界
                    if(reverse  maxValue_10) {
                        return 0;
                    } else if(reverse == maxValue_10) {
                        if(digit  maxValueMod) {
                            return 0;
                        }
                    }
                } else {
                    // 判断负数是否越界
                    if(reverse  minValue_10) {
                        return 0;
                    } else if(reverse == minValue_10) {
                        if(digit  minValueMod) {
                            return 0;
                        }
                    }
                }
                reverse = reverse * 10 + digit;
            }
    
            return reverse;
        }
    }
    

    复杂度分析:
    时间复杂度: O(n),表示有 n位数字
    空间复杂度: O(1)

    9. 回文数

    本题来自 LeetCode:9. 回文数[2]

    题目描述

    判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
    示例 1:

    
    输入: 121
    输出: true
    

    示例  2:

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

    示例 3:

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

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

    解法一

    题目分析

    本题判断一个整数是否为回文数,可以通过将整数的每一位的数字按顺序存储到数组中,最后判断该数组是否为回文数组即可。
    注意负数不是回文数。

    题目解答

    
    class Solution {
        public boolean isPalindrome(int x) {
            if(x  0) {
                return false;
            }
            int n = 0;
            ListInteger digits = new ArrayList();
            while(x != 0) {
                digits.add(x % 10);
                x /= 10;
            }
            int left = 0;
            int right = digits.size() - 1;
            while(left = right) {
                if(digits.get(left) != digits.get(right)) {
                    return false;
                }
                left ++;
                right --;
            }
            return true;
        }
    }
    

    复杂度分析:
    时间复杂度: O(n) n为整数数字位数。空间复杂度: O(n)

    解法二

    题目分析

    解法一使用了额外的空间,也可以通过题 7. 整数反转的思路,将整数反转后,直接和原整数比较是否相等。需要注意判断是否越界的问题。

    题目解答

    
    class Solution {
        public boolean isPalindrome(int x) {
            // 负数不是回文数
            if(x  0) {
                return false;
            }
            // 存储反转后的整数
            int y = 0;
            int temp = x;
            // 反转整数
            while(temp != 0) {
                int digit = temp % 10;
                // 判断是否越界
                if(y  Integer.MAX_VALUE / 10
                    || (y == Integer.MAX_VALUE / 10 && digit  Integer.MAX_VALUE % 10)) {
                    return false;
                }
                y = y * 10 + digit;
                temp /= 10;
            }
            // 判断反转后的整数和原整数是否相等
            return x == y;
        }
    }
    

    复杂度分析:
    时间复杂度: O(n)
    空间复杂度: O(1)

    8. 字符串转换整数 (atoi)

    本题来自 LeetCode:8. 字符串转换整数 (atoi)[3]

    题目描述

    请你来实现一个  atoi  函数,使其能将字符串转换成整数。
    首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
    当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
    该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
    注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
    在任何情况下,若函数不能进行有效的转换时,请返回 0。
    说明:
    假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为  [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或  INT_MIN (−231) 。示例  1:

    
    输入: "42"
    输出: 42
    

    示例  2:

    
    输入: "   -42"
    输出: -42
    解释: 第一个非空白字符为 '-', 它是一个负号。
         我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42

    示例  3:

    
    输入: "4193 with words"
    输出: 4193
    解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
    

    示例  4:

    
    输入: "words and 987"
    输出: 0
    解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
         因此无法执行有效的转换。
    

    示例  5:

    
    输入: "-91283472332"
    输出: -2147483648
    解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
         因此返回 INT_MIN (231)

    题目分析

    本题是一条体力题,需要注意好各细节问题。可以分析成三步来解答。

  • 跳过字符串开头的所有空格。
  • 校验第一个字符是否合法,并确定正负。
  • 将连续的字符串数字转换有效的数值`num`,同时也判断整数是否越界(参考`7. 整数反转`题)。
  • 题目解答

    
    class Solution {
        public int myAtoi(String str) {
            if(str == null && str.length() == 0) {
                return 0;
            }
            // 1. 跳过字符串开头的所有空格
            int i = 0;
            while(i  str.length() && str.charAt(i) == ' ') {
                i ++;
            }
            if(i = str.length()) {
                return 0;
            }
    
            // 2. 校验第一个字符是否合法,并确定正负
            int flag = 1;
            char first = str.charAt(i);
            if(first == '-') {
                flag = -1;
                i ++;
            } else if(first == '+') {
                i ++;
            } else if(first - '0'  0 || first - '0'  9) {
                return 0;
            }
    
            // 3. 转换有效的字符
            int num = 0;
            while(i  str.length()) {
                int digit = str.charAt(i) - '0';
                if(digit  0 || digit  9) {
                    return num;
                }
                digit *= flag;
                // 判断是否越界
                if(num = 0) {
                    // 正整数越界
                    if(num  Integer.MAX_VALUE / 10
                        || (num == Integer.MAX_VALUE / 10 && digit  Integer.MAX_VALUE % 10)) {
                            return Integer.MAX_VALUE;
                        }
                } else {
                    // 负整数越界
                    if(num  Integer.MIN_VALUE / 10
                        || (num == Integer.MIN_VALUE / 10 && digit  Integer.MIN_VALUE % 10)) {
                            return Integer.MIN_VALUE;
                        }
                }
                num = num * 10 + digit;
                i ++;
            }
    
            return num;
        }
    }
    

    复杂度分析:
    时间复杂度: O(n)
    空间复杂度: O(1)

    190. 颠倒二进制位

    本题来自 LeetCode:190. 颠倒二进制位[4]

    题目描述

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

    
    输入: 00000010100101000001111010011100
    输出: 00111001011110000010100101000000
    解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
          因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000

    示例 2:

    
    输入:11111111111111111111111111111101
    输出:10111111111111111111111111111111
    解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
     因此返回 3221225471 其二进制表示形式为 10101111110010110010011101101001

    提示:
    请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
    在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的   示例 2  中,输入表示有符号整数 -3,输出表示有符号整数 -1073741825。
    进阶:
    如果多次调用这个函数,你将如何优化你的算法?

    题目分析

    题目解答

    
    public class Solution {
        // you need treat n as an unsigned value
        public int reverseBits(int n) {
            int reverse = 0;
            int count = 0;
            while(n != 0) {
                reverse = (reverse  1) | (n & 1);
                n = 1;
                count ++;
            }
            // 补足32位
            while(count  32) {
                reverse = 1;
                count ++;
            }
            return reverse;
        }
    }
    

    复杂度分析:
    时间复杂度: O(1)
    空间复杂度: O(1)

    参考资料

    1. 整数反转: https://leetcode-cn.com/problems/reverse-integer

    2. 回文数: https://leetcode-cn.com/problems/palindrome-number

    3. 字符串转换整数 (atoi): https://leetcode-cn.com/problems/string-to-integer-atoi/

    4. 颠倒二进制位: https://leetcode-cn.com/problems/reverse-bits

    原文始发于微信公众号(xiaogan的技术博客):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> 整数反转相关题型


     上一篇
    988. 从叶结点开始的最小字符串 988. 从叶结点开始的最小字符串
    本题来自 LeetCode:988. 从叶结点开始的最小字符串[1] 题目描述给定一颗根结点为  root  的二叉树,书中的每个结点都有一个从  0 到  25  的值,分别代表字母  ‘a’ 到  ‘z’:值  0 代表  ‘a’,值
    2021-04-05
    下一篇 
    118&119. 杨辉三角I & II 118&119. 杨辉三角I & II
    118. 杨辉三角本题来自 LeetCode:118. 杨辉三角[1] 题目描述给定一个非负整数  numRows,生成杨辉三角的前  numRows  行。在杨辉三角中,每个数是它左上方和右上方的数的和。示例: 输入: 5 输出: [
    2021-04-05