数组 / 加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。你可以假设这个整数不会以零开头。

仔细审题,会发现题干中给出了好几个预备条件。
(1)非空数组
(2)非负整数
(3)第一个数不会是0开头

数组元素的个数,就等于整数的位数。加一问题看似简单,直接在数组上操作却需要考虑情况多样的进位问题,有些复杂。因此不如先把数组转换成long/int,加一之后再重新转换回数组。

其中逻辑最复杂的部分,就是把int转换回数组的部分。需要循环取模。

此处的代码如果这样写,将无法应对位数增加的情况。比如输入9,加一之后位数+1,变成10。而遍历的循环变量边界还是以原始的9的长度为边界,因此结果一定是错误的。

循环处的i能够取的值,代表了会进行多少次循环。如果直接修改边界条件,会给所有的情况都增加一位数字。显然是有问题的。

从逻辑分析的角度上说,只能把这种特殊情况单独拎出来处理;或者有一种判断的方法,能够区分是否进位。

  for (int i = 0; i < n ; i++) {
            long t = (long) Math.pow(10, n - i - 1);
            digits[i] = (int) (num / t % 10);
  }

其实上面代码不能处理的情况,只有一种:位数加1的情况。而位数+1的情况,只会出现在所有位数都是9的情况下。因此就对这种情况做分离处理,代码如下:

while (c <= digits.length) {
            int t = (int) (num / Math.pow(10, 1) % 10);
            if (((int)(num / Math.pow(10, n - c - 1)) % 10 == 9)) {
                c++;
                continue;
            } else if (c == n) {
                result = new int[++n];
            } else {
                result = new int[n];
                break;
            }
}

但上面的做法最大的问题是,无法应对超长数组的转换。在基本类型中long已经是能够表示的最大的数。然而输入的数组却会轻而易举超过long能表示的极限,因此这个方法其实并不合适。

因此,如果我们直接对数组进行操作。正如上文所说,最复杂的情况出现在位数+1的时候。其余的进位情况,只是对该位的前一位+1即可。

进位只会出现在从末尾开始连续9出现的情况下。比如9,89,29,239,299。从末尾开始数,出现一个9则进一位,出现两个9则进两位。话句话说,这个数组中,只有数字9是特别的,并且必须是连续的9,比如989就只能算作出现了一个连续的9。

因此,可以写一个循环,从数组的末尾开始,寻找连续9的个数。如果是0个,直接末位数+1即可;如果是1个9,则出现9的位数变为0,它的前一位+1;如果是2个9,则末尾两位都变成0,前两位+1(比如99->100,或者799->800)。还需要确认的是,是否9的位数与数字本身的位数相等。

代码如下:

public int[] plusOne(int[] digits) {
        int n = digits.length;
        int count = 0;
        int i = n - 1;
        boolean flag = false;
        int[] result;
        // 统计连续9出现的次数
        while (digits[i] == 9 && i>=0) {
            count++;
            i--;
        }
        // 判断位数与9出现的次数是否相等
        if (count == n)
            flag = true;
        // 如果出现了全是9的情况,则位数+1
        if (flag == true) {
            result = new int[n+1];
            result[0] = 1;
            return result;
        }
        // 出现了几次9,就把末尾几位变为0,并把前一位进1
        int count1 = count;
        while (count > 0) {
            digits[n - count] = 0;
            count--;
        }
        // 如果count==0,则进行普通+1操作
        digits[n-count1-1]++;
        return digits;
    }

以上代码的时间复杂度非常优秀,是我第一次写出执行时间1ms的代码。可见世界上不会有白花的功夫——虽然上一种解法失败了,却加深了我对本题的理解。因此才能逻辑清晰地写出第二种解答。

以上。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,270评论 0 4
  • 前言 2. 实现 Singleton 3. 数组中重复的数字 4. 二维数组中的查找 5. 替换空格 6. 从尾到...
    Observer_____阅读 2,990评论 0 1
  •   引用类型的值(对象)是引用类型的一个实例。   在 ECMAscript 中,引用类型是一种数据结构,用于将数...
    霜天晓阅读 1,092评论 0 1
  • 数组是最简单的数据结构,占据连续内存并且按顺序存储。 以下是与数组有关的算法题目。 (1)查询数组中重复数字 算法...
    顽皮的石头7788121阅读 2,128评论 0 0
  • 1. 找出数组中重复的数字 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,...
    BookThief阅读 1,815评论 0 2