力扣66. 加一

来源:66. 加一 - 力扣(LeetCode)

加一:Java解法详解

目录

加一:Java解法详解

题目

 详解

方法一:暴力手撕法

思路

代码详解 

核心知识点  BigInteger

BigInteger常见的方法

方法二:找出最长的后缀 9

思路

算法

特殊情况考虑


题目

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。

示例 2:

输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。

示例 3:

输入:digits = [9]
输出:[1,0]
解释:输入数组表示数字 9。
加 1 得到了 9 + 1 = 10。
因此,结果应该是 [1,0]。

提示:

  • 1 <= digits.length <= 100

  • 0 <= digits[i] <= 9

 详解

方法一:暴力手撕法

思路

此方法采用最直接的暴力破解思路,其具体实现步骤如下:

数组转整数阶段:

  1. 首先遍历给定数组中的每个数字元素
  2. 通过位运算或乘10累加的方式,将数组数字拼接成一个完整的整数
  3. 例如数组[1,2,3]会转化成整数123

整数加一运算 

  1. 对转化后的整数执行简单的加一操作
  2. 需要注意处理可能的整数溢出问题
  3. 接上例,123加一变为124

 整数转数组阶段

  1. 将加一后的整数转换为字符串形式
  2. 逐个字符提取并转化回数字,组成新数组
  3. 124会被拆分为数组[1,2,4]

代码详解 

import java.math.BigInteger;

class Solution {
    public int[] plusOne(int[] digits) {
        // 获取 digits 数组的长度
        int n = digits.length; 
        // 初始化 BigInteger 变量 m 为 0
        BigInteger m = BigInteger.ZERO;

        // 提取 digits 里的元素组成一个整数
        for (int i = 0; i < n; i++) {
            // 将 digits[i] 加到 m 的相应位置
            m = m.multiply(BigInteger.TEN).add(BigInteger.valueOf(digits[i]));
        }

        // 计算 n 位数中所有位都是 9 的情况
        BigInteger allNines = BigInteger.TEN.pow(n).subtract(BigInteger.ONE); 
        if (m.equals(allNines)) {
            // 创建一个长度为 n + 1 的结果数组
            int[] result = new int[n + 1];
            // 将最高位设为 1
            result[0] = 1;
            // 返回结果数组
            return result; 
        } else {
            // 创建一个长度为 n 的结果数组
            int[] result = new int[n];
            // 将 m 加 1
            m = m.add(BigInteger.ONE); 
            for (int i = n - 1; i >= 0; i--) {
                // 获取 m 的最后一位并存储到结果数组
                result[i] = m.mod(BigInteger.TEN).intValue();
                // 去掉 m 的最后一位
                m = m.divide(BigInteger.TEN); 
            }
            return result; // 返回结果数组
        }
    }
}

为避免整数溢出风险,建议采用大整数库(如Java的BigInteger)来处理超出标准范围的数值转换

核心知识点  BigInteger

方法来源:BigInteger (Java Platform SE 8 )

将数组转换为整数时,数组元素的数量直接决定了最终整数的位数,这是一个需要特别注意的关键因素。不同编程语言和系统环境对整数的存储大小有不同限制。

在32位系统中,整数通常被限制在-2,147,483,648到2,147,483,647( (-2^{31}) 到 (2^{31} - 1))之间,这意味着最多只能处理10位数的数组转换(考虑正数情况)。而在64位系统中,虽然范围扩大到-9,223,372,036,854,775,808到9,223,372,036,854,775,807( (-2^{63}) 到 (2^{63} - 1)),但仍然有19位数字的限制。

实际应用中,必须进行以下检查:

  1. 预先计算数组长度,评估可能产生的整数位数
  2. 根据运行环境的整数类型限制(如int32/int64)进行边界检查
  3. 考虑使用大整数库(Java的BigInteger)来处理超出常规范围的转换
  4. 在转换前对数组元素进行验证,确保所有元素都是0-9之间的数字

例如,在转换一个包含20个元素的数组时,即使所有元素都是1,也会产生一个超过64位整数最大值的数字(1,111,111,111,111,111,111,111),这时就必须使用特殊的大整数处理方式,否则会导致数值溢出错误,可能引发程序异常或计算出错。

BigInteger常见的方法

BigInteger类提供了许多方法来处理大整数。以下是一些常见的方法:

 1. 构造方法:
    
    · BigInteger(String val): 将字符串转换为BigInteger。
    · BigInteger(int[] val): 将整数数组转换为BigInteger。
    · BigInteger(byte[] val): 将字节数组转换为BigInteger。
    · BigInteger(int bitLength, Random rnd): 生成一个随机的BigInteger,其位长度为bitLength。

 2. 基本运算:
    
    · add(BigInteger val): 返回此BigInteger与指定BigInteger的和。
    · subtract(BigInteger val): 返回此BigInteger与指定BigInteger的差。
    · multiply(BigInteger val): 返回此BigInteger与指定BigInteger的乘积。
    · divide(BigInteger val): 返回此BigInteger除以指定BigInteger的商。
    · mod(BigInteger m): 返回此BigInteger除以指定BigInteger的余数。

 3. 比较:
    
    · equals(Object x): 比较此BigInteger与指定对象是否相等。
    · compareTo(BigInteger val): 比较此BigInteger与指定BigInteger的大小。

 4. 位运算:
    
    · and(BigInteger val): 返回此BigInteger与指定BigInteger的按位与。
    · or(BigInteger val): 返回此BigInteger与指定BigInteger的按位或。
    · xor(BigInteger val): 返回此BigInteger与指定BigInteger的按位异或。
    · not(): 返回此BigInteger的按位非。
    · shiftLeft(int n): 返回此BigInteger的左移。
    · shiftRight(int n): 返回此BigInteger的右移。

 5. 其他:
    
    · abs(): 返回此BigInteger的绝对值。
    · negate(): 返回此BigInteger的负数。
    · pow(int exponent): 返回此BigInteger的指定次方。
    · gcd(BigInteger val): 返回此BigInteger与指定BigInteger的最大公约数。
    · modInverse(BigInteger m): 返回此BigInteger模m的模逆。
    · modPow(BigInteger exponent, BigInteger m): 返回此BigInteger的exponent次方模m。

BigInteger.ZERO 是 BigInteger 类的一个静态常量,表示值为 0 的 BigInteger 对象。类似这样的静态常量还有以下几个:

  1. BigInteger.ZERO:

    • 表示值为 0 的 BigInteger 对象。

  2. BigInteger.ONE:

    • 表示值为 1 的 BigInteger 对象。

  3. BigInteger.TEN:

    • 表示值为 10 的 BigInteger 对象。

BigInteger a = BigInteger.ZERO;  // a 的值为 0
BigInteger b = BigInteger.ONE;   // b 的值为 1
BigInteger c = BigInteger.TEN;   // c 的值为 10

这些静态常量可以直接使用,而不需要每次都通过构造函数创建新的 BigInteger 对象,从而提高代码的可读性和效率。

方法二:找出最长的后缀 9

思路

当我们对数组 digits 加一时,我们只需要关注 digits 的末尾出现了多少个 9 即可。我们可以考虑如下的三种情况:

  1. 如果 digits 的末尾没有 9,例如 [1,2,3],那么我们直接将末尾的数加一,得到 [1,2,4] 并返回;
  2. 如果 digits 的末尾有若干个 9,例如 [1,2,3,9,9],那么我们只需要找出从末尾开始的第一个不为 9 的元素,即 3,将该元素加一,得到 [1,2,4,9,9]。随后将末尾的 9 全部置零,得到 [1,2,4,0,0] 并返回。
  3. 如果 digits 的所有元素都是 9,例如 [9,9,9,9,9],那么答案为 [1,0,0,0,0,0]。我们只需要构造一个长度比 digits 多 1 的新数组,将首元素置为 1,其余元素置为 0 即可。

算法

只需要对数组 digits 进行一次逆序遍历,找出第一个不为 9 的元素,将其加一并将后续所有元素置零即可。如果 digits 中所有的元素均为 9,那么对应着「思路」部分的第三种情况,我们需要返回一个新的数组。

特殊情况考虑

输入:digits = [9]

输出:[1,0]

输入:digits = [9,9,9,9]

输出:[1,0,0,0,0]

输入:digits = [6,9,9,9]

输出:[7,0,0,0]

import java.util.Arrays;
class Solution {
    public int[] plusOne(int[] digits) {
        int n = digits.length;
        if (n==1 && digits[0] == 9){
            int[] result = new int[n+1];
            result[0] = 1;
            return result;
        }
        for (int i = n-1;i>=0;i--){
            if (i != 0&&digits[i] == 9){
                digits[i] = 0;
                continue;
            }
            if(digits[i] != 9){
                digits[i] = digits[i] + 1;
                //
                return digits;
            }else if(i ==0 && digits[i] ==9){
                int[] result = new int[n+1];
                result[0] = 1;
                return result;
            }
        }
        return digits;


}
}
public class Main {
    public static void main(String[] args){
        int[] digits = {8,9,9,9};
        Solution solution = new Solution();
        int[] result = solution.plusOne(digits);
        System.out.println(Arrays.toString(result));
}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值