加一:Java解法详解
目录
题目
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 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
详解
方法一:暴力手撕法
思路
此方法采用最直接的暴力破解思路,其具体实现步骤如下:
数组转整数阶段:
- 首先遍历给定数组中的每个数字元素
- 通过位运算或乘10累加的方式,将数组数字拼接成一个完整的整数
- 例如数组[1,2,3]会转化成整数123
整数加一运算
- 对转化后的整数执行简单的加一操作
- 需要注意处理可能的整数溢出问题
- 接上例,123加一变为124
整数转数组阶段
- 将加一后的整数转换为字符串形式
- 逐个字符提取并转化回数字,组成新数组
- 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位数字的限制。
实际应用中,必须进行以下检查:
- 预先计算数组长度,评估可能产生的整数位数
- 根据运行环境的整数类型限制(如int32/int64)进行边界检查
- 考虑使用大整数库(Java的BigInteger)来处理超出常规范围的转换
- 在转换前对数组元素进行验证,确保所有元素都是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
对象。类似这样的静态常量还有以下几个:
-
BigInteger.ZERO
:-
表示值为 0 的
BigInteger
对象。
-
-
BigInteger.ONE
:-
表示值为 1 的
BigInteger
对象。
-
-
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 即可。我们可以考虑如下的三种情况:
- 如果 digits 的末尾没有 9,例如 [1,2,3],那么我们直接将末尾的数加一,得到 [1,2,4] 并返回;
- 如果 digits 的末尾有若干个 9,例如 [1,2,3,9,9],那么我们只需要找出从末尾开始的第一个不为 9 的元素,即 3,将该元素加一,得到 [1,2,4,9,9]。随后将末尾的 9 全部置零,得到 [1,2,4,0,0] 并返回。
- 如果 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));
}}