LeetCode_66
题目:
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pl
解法
思路一:我们可以将数组里面的元素先转化为数字,然后加1之后然后在放入数组。
思路二:我们直接让数组最后一位加1就行了
但是:思路确实没错,但是我们要考虑有没有特殊情况,已知数组不为空那么这种情况我们就不考虑了。那如果加1之后产生了进位呢?如果全部是9呢,就是数字位数变成了n+1位了呢?
针对思路一的特殊情况的解法:定义一个变量将数组元素按位数转化为的数值存起来,然后判断是否变成了10000...这种形式的数,如果是,那么对原数组扩容,arr[0] = 1就行了,如果不是,那么直接放入原数组。返回。
针对思路二的特殊情况的解法:写一个倒循环,遍历原数组arr,并且直接从最后一位开始将arr[i]+1的值赋给一个变量num;然后让num]对10取余,如果不为0,那就arr[i]++;return arr;(注意,第一次加1的值赋给了num参与判断,而此时的arr[i]并没有加1,先用变量判断,可以直接加在加),如果为0,也就是说产生了进位,那就将arr[i] = 0;然后不用管了。
思路二的核心思想是,先用将加1的值赋给变量,本身不改变值;然后用这个变量去判断有没有进位,有进位,变0,i--;没进位,+1返回。
思路一代码:
public class LC66_2 {
public static void main(String[] args) {
int [] arr = {1,3,4}; //普通测试用例1
int [] arr2 = {9,9,9}; //特殊测试用例2
arr = plusOne(arr); //传入测试数组1
printArr(arr); //打印加一后的数组
arr2 = plusOne(arr2); //传入测试用例2
printArr(arr2); //打印加一后的数组
}
public static int[] plusOne(int[] arr) { //加一的方法实现
int num = 0;
for (int i = 0; i < arr.length; i++) {
num = num*10 + arr[i]; //将数组转化为数字
}
int numNew = num + 1; //转化为数字后+1得到目标数字
if(!IsCarry(numNew)) { //IsCarry(numNew)是判断+1后的数字是否产生进位,产生返回true,否则false
arr = numToArr(numNew,arr.length); //没有产生进位则numToArr(numNew,arr.length)是将数字转化为数组,返回目标数组
}else {
arr = addArrLen(arr); //产生了进位则必然是1000.。。。这样得形式,
//对原数组进行扩容+1个长度,让arr指向新数组首地址
}
return arr; //返回arr
}
public static int[] addArrLen(int[] arr) { //实现扩容的方法
int [] arrNew = new int[arr.length + 1]; //定义一个新的数组,长度比原来的数组长度多1
arrNew[0] = 1; //直接将新数组角标为0的元素赋值为1,其余因为初始化的原因为0,达到目的
return arrNew; //达到目的返回新数组
}
public static int[] numToArr(int numNew,int len) {//实现数字转化为数组的方法
int [] arr = new int[len]; //先定义一个数组长度为len
for (int i = arr.length - 1; i >= 0; i--) {
arr[i] = numNew%10; //辗转取余和除,求得得个数赋值给arr[i]
numNew = numNew / 10;
}
return arr;
}
public static boolean IsCarry(int numNew) { //实现判断是否产生进位得方法
int sum = 0;
while(numNew>0) { //直接看所有位相加结果是否为1
sum += numNew%10;
numNew /= 10;
}
if(sum == 1) {
return true;//是特殊情况
}
return false;//不是特殊情况
}
public static void printArr(int[] arr) { //实现打印方法
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length - 1) {
System.out.print(arr[i] + "]");
}else {
System.out.print(arr[i] + ",");
}
}
System.out.println("");
}
}
思路二代码:
public class LC66T {
public static void main(String[] args) {
//定义测试数组1
int arr1[] = {1,2,3,4};
//调用加一方法
arr1 = getPlusOne(arr1);
//打印加一后的测试数组1
print(arr1);
//定义测试数组2
int arr2[] = {9,9,9,9};
//调用加一方法
arr2 = getPlusOne(arr2);
//打印加一后的测的数组2
print(arr2);
}
public static int[] getPlusOne(int[] arr) {
//首先从数组最后一位开始遍历
for (int i = arr.length - 1; i >= 0; i--) {
//定义一个num来存储当前数组位值加一后的变化,但此时该位并未真正加一
int num = arr[i] + 1;
//定义一个carry存储num%10取余的结果
int carry = num % 10;
//若carry == 0,说明当前数加一后产生了进位
if(carry == 0) {
//既然产生了进位,那么该位就的变成0,因此直接赋值
arr[i] = 0;
}else {
//如果没有产生进位,那么该位加一就行
arr[i]++;
//返回数组
return arr;
}
}
//但若是程序能运行到这里
int [] arrNew = new int [arr.length + 1];
//便说明传进来的数组值都是9,最高为都进位了
//原数组长度不够,因此扩容,并arr[0]位直接为1就行了
arrNew[0] = 1;
return arrNew; //返回新数组
}
public static void print(int [] arr) { //打印方法
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i!=arr.length - 1) {
System.out.print(arr[i] + ",");
}else {
System.out.print(arr[i] + "]");
}
}
}
}
总结:
一个题思路会有很多,没有最好,没有最优,但是我们尽可能的选择灵活,复杂度小的解法。
这题主要在于加一之后处理进位的问题,我觉得我的解法二有一个灵活之处在于一开始我并没有对最后一个数直接加一,而是用了一个num先存储加一后的值,在拿这个值去判断是否产生了进位,如果真的进位了,那我便直接让当前这个值为零。否则就直接加一。这种思路和想法其实是比较灵活的。也就是说,当一个值或说一个事物的改变还会对这个值或说这个事物造成二次改变,那么我们就不能贸然去改变这个值,应该先模拟,先试探,得出了结果再去改变。并且要注意因为一个值得改变带来得连锁反应,比如这一题,一个值改变,可能进位,那么他前面得值也得改,甚至全部进位那还得扩容。
完!