【经典算法】LeetCode 66. 加一(Java/C/Python3实现含注释说明,简单)

题目描述

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

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

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

示例 1:

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

示例 2:

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

思路及实现

方式一:反转数组后逐位相加

思路

首先,将数组反转,然后从最低位开始逐位相加。如果相加后的数值大于 9,则会产生进位,将进位保存到临时变量中。对于每一位的相加结果,直接赋值给反转后的对应位置,并且要注意处理进位。

完成所有位的相加后,检查最高位是否还有进位,如果有,则在数组最前面插入 1。

最后,再次反转数组,得到最终的结果。

代码实现

Java版本
class Solution {
    public int[] plusOne(int[] digits) {
        int n = digits.length;
        // 反转数组
        reverse(digits, 0, n - 1);

        int carry = 1; // 初始化进位为 1
        for (int i = 0; i < n; i++) {
            int sum = digits[i] + carry;
            digits[i] = sum % 10; // 取个位数
            carry = sum / 10; // 更新进位
        }

        // 如果最高位还有进位,则在数组最前面插入 1
        if (carry > 0) {
            int[] newDigits = new int[n + 1];
            newDigits[0] = carry;
            System.arraycopy(digits, 0, newDigits, 1, n);
            return newDigits;
        }

        // 再次反转数组得到最终结果
        reverse(digits, 0, n - 1);
        return digits;
    }

    // 反转数组指定区间内的元素
    private void reverse(int[] digits, int start, int end) {
        while (start < end) {
            int temp = digits[start];
            digits[start] = digits[end];
            digits[end] = temp;
            start++;
            end--;
        }
    }
}

说明:

该实现首先将数组反转,方便从最低位开始逐位相加。使用reverse函数辅助反转数组指定区间的元素。完成逐位相加后,再次检查进位,并根据情况创建新数组或在原数组最前面插入 1。最后再次反转数组,得到最终的结果。

C语言版本
#include <stdlib.h>
#include <string.h>

void reverse(int *digits, int start, int end) {
    while (start < end) {
        int temp = digits[start];
        digits[start] = digits[end];
        digits[end] = temp;
        start++;
        end--;
    }
}

int* plusOne(int* digits, int digitsSize, int* returnSize) {
    int carry = 1;
    int *result = (int *)malloc((digitsSize + 1) * sizeof(int));
    if (!result) return NULL;

    // 反转数组
    reverse(digits, 0, digitsSize - 1);

    // 逐位相加
    for (int i = 0; i < digitsSize; i++) {
        int sum = digits[i] + carry;
        result[i] = sum % 10;
        carry = sum / 10;
    }

    // 处理最高位进位
    if (carry > 0) {
        result[digitsSize] = carry;
        *returnSize = digitsSize + 1;
    } else {
        *returnSize = digitsSize;
    }

    // 再次反转数组
    reverse(result, 0, *returnSize - 1);
    return result;
}

说明:

C语言版本与

思路及实现

方式二:从最高位开始逐位相加

思路

从数组的最高位(即数组末尾)开始逐位相加,如果当前位相加后的结果大于等于 10,则需要向高位进位。特别地,需要关注最高位是否有进位产生,如果有,则需要在数组最前面插入一个数字 1。

为了避免处理数组扩容问题,可以从数组末尾向前遍历,用一个变量来记录是否产生进位,并相应地更新数组元素。

代码实现

Java版本
class Solution {
    public int[] plusOne(int[] digits) {
        int n = digits.length;
        int carry = 1; // 初始化进位为 1
        for (int i = n - 1; i >= 0; i--) {
            int sum = digits[i] + carry;
            digits[i] = sum % 10; // 取个位数
            carry = sum / 10; // 更新进位
            if (carry == 0) {
                // 如果进位为 0,则无需继续向前遍历
                break;
            }
        }

        // 如果最高位还有进位,则在数组最前面插入 1
        if (carry > 0) {
            int[] newDigits = new int[n + 1];
            newDigits[0] = carry;
            System.arraycopy(digits, 0, newDigits, 1, n);
            return newDigits;
        }

        return digits;
    }
}

说明:

该实现从数组末尾开始逐位相加,并更新进位。如果最高位还有进位,则创建新数组并在最前面插入 1。否则,直接返回原数组(因为数组长度可能不变)。

C语言版本
#include <stdlib.h>

int* plusOne(int* digits, int digitsSize, int* returnSize) {
    int carry = 1;
    int *result = (int *)malloc(digitsSize * sizeof(int));
    if (!result) return NULL;
    
    int i;
    for (i = digitsSize - 1; i >= 0; i--) {
        int sum = digits[i] + carry;
        result[i] = sum % 10;
        carry = sum / 10;
        if (carry == 0) {
            break;
        }
    }

    if (carry > 0) {
        // 如果最高位还有进位,则需要扩容数组
        int *newResult = (int *)realloc(result, (digitsSize + 1) * sizeof(int));
        if (!newResult) {
            free(result);
            return NULL;
        }
        result = newResult;
        result[0] = carry;
        *returnSize = digitsSize + 1;
    } else {
        *returnSize = i + 1; // 更新返回数组的长度
    }

    return result;
}

说明:

C语言版本的实现逻辑与 Java 版本相似,但需要注意内存管理。在可能需要扩容数组时,使用 realloc 函数重新分配内存,并检查是否分配成功。

Python3版本
class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        carry = 1
        n = len(digits)
        for i in range(n - 1, -1, -1):
            sum_val = digits[i] + carry
            digits[i] = sum_val % 10
            carry = sum_val // 10
        
        if carry > 0:
            digits.insert(0, carry)
        
        return digits

说明:

Python 版本的实现相对简洁,因为 Python 列表可以动态扩容,无需显式管理内存。从列表末尾开始遍历,更新进位和元素值,如果最高位有进位,则在列表最前面插入 1。

Golang版本

如果 carry 仍然大于 0,这意味着原始数组的最高位也发生了进位,需要在数组的最前面插入一个数字 1。在 Golang 中,我们不能像 Python 那样简单地使用 insert 方法,因为 Go 的切片是固定长度的,我们需要创建一个新的切片来容纳这个额外的元素。

下面是 Golang 版本的完整实现:

func plusOne(digits []int) []int {
    n := len(digits)
    carry := 1
    
    // 从后向前遍历数组,处理进位
    for i := n - 1; i >= 0; i-- {
        sum := digits[i] + carry
        digits[i] = sum % 10
        carry = sum / 10
    }
    
    // 如果最高位仍有进位,则需要在数组最前面插入一个 1
    if carry > 0 {
        // 创建一个新的切片,长度比原切片多 1
        newDigits := make([]int, n+1)
        // 将原切片的元素复制到新切片的相应位置
        copy(newDigits[1:], digits)
        // 在新切片的最前面插入进位值 1
        newDigits[0] = carry
        // 返回新切片
        return newDigits
    }
    
    // 如果没有进位,直接返回原切片
    return digits
}

在这个实现中,我们首先处理了数组中的进位,然后检查是否需要在数组最前面插入一个数字 1。如果需要,我们创建了一个新的切片 newDigits,它的长度比原切片 digits 多 1,然后将原切片的元素复制到新切片的从索引 1 开始的位置,最后将进位值 1 插入到新切片的最前面。如果没有进位发生,我们则直接返回原切片。

请注意,这个实现假设输入的切片 digits 至少包含一个元素,因为题目要求是对一个非空数组进行操作。如果需要对空数组进行处理,那么还需要添加额外的边界检查。此外,由于 Go 语言的切片是引用类型,因此返回新的切片时,实际上返回的是对底层数组的引用,这不会造成额外的内存开销(除了可能的新切片本身)。

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值