每日一恋 - LeetCode 2 & 445 & 66 & 67 & 415. 数字相加

2. 两数相加

给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

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

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

分析

链表是倒序存储,相对较容易,只要同时遍历两个链表,将两数相加再加上进位,位数不够以0处理,然后将本次的进位和本次的答案记录下来。

注意最后要处理首位的进位。

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

   ListNode dummyNode = new ListNode(-1);
   ListNode a = l1, b = l2, cur = dummyNode;

   int carry = 0;
   while (a != null || b != null) {

       int x = a == null ? 0 : a.val;
       int y = b == null ? 0 : b.val;
       int tmp = x + y + carry;
       carry = tmp / 10;
       cur.next = new ListNode(tmp % 10);
       cur = cur.next;
       if (a != null) a = a.next;
       if (b != null) b = b.next;
   }
   if (carry > 0) {
       cur.next = new ListNode(carry % 10);
   }
   return dummyNode.next;
}

445. 两数相加 II

给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。

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

进阶:

如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

示例:

输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7

分析

这道题与上一题的区别在于链表是正序的,导致链表的遍历方向与数字的加运算相反,我们可以使用栈结构来保存链表的数值,再从栈中取出进行运算。

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

    Stack<Integer> s1 = new Stack<Integer>();
    Stack<Integer> s2 = new Stack<Integer>();

    while (l1 != null) {
        s1.push(l1.val);
        l1 = l1.next;
    }
    while (l2 != null) {
        s2.push(l2.val);
        l2 = l2.next;
    }
    int x, y, carry = 0;
    ListNode p = null;
    ListNode next = null;
    while (!s1.isEmpty() || !s2.isEmpty()) {
        x = s1.isEmpty() ? 0 : s1.pop();
        y = s2.isEmpty() ? 0 : s2.pop();
        int tmp = x + y + carry;
        next = new ListNode(tmp % 10);
        next.next = p;
        p = next;
        carry = tmp / 10;
    }
    if (carry > 0) {
        next = new ListNode(1);
        next.next = p;
    }
    return next;
}

另一种递归的思路,通过判断两个链表的长度,得到其偏移量,在偏移量不为0时,就只取长度更长的链表的节点,每次递归偏移量都减一,当减为0时,说明两个链表的节点都可以参与运算了,直到其中两个同时遍历完成时递归进行返回。

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

    int size1 = getCount(l1);
    int size2 = getCount(l2);
    ListNode head = new ListNode(1);
    // 确保长度 l1 大于 l2
    head.next = size1 > size2 ? helper(l1, l2, size1 - size2) : helper(l2, l1, size2 - size1);
    // 处理进位
    if (head.next.val > 9) {
        head.next.val = head.next.val % 10;
        return head;
    }
    return head.next;
}

public int getCount(ListNode l) {
    int count = 0;
    while (l != null) {
        l = l.next;
        count ++;
    }
    return count;
}
// offset是 l1 和 l2 之间的长度偏移量
public ListNode helper(ListNode l1, ListNode l2, int offset) {
    if (l1 == null) return null;

    // 如果偏移量等于0,说明可以将两者的节点加起来,否则就只加长度更长的l1
    ListNode result = offset == 0 ? new ListNode(l1.val + l2.val) : new ListNode(l1.val);
    // 确保递归的退出
    ListNode next = offset == 0 ? helper(l1.next, l2.next, 0) : helper(l1.next, l2, offset - 1);
    // 处理进位
    if (next != null && next.val > 9) {
        result.val += 1;
        next.val = next.val % 10;
    }
    // 连接节点
    result.next = next;
    return result;
}

需要注意的就是,每次递归都需要将当前节点连接下一个节点,然后返回当前节点,层层递归最后就可以得到答案。


66. 加一

给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组。

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

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

示例 1:

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

示例 2:

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

分析

题目很简单,但要注意几点:

  1. 计算顺序应从数组的最后一个数字开始
  2. 加一在操作如果放在循环里面,只在第一次的时候加一
  3. 确定最后的数组大小,数字加一后会不会进位
public int[] plusOne(int[] digits) {

   LinkedList<Integer> list = new LinkedList<Integer>();

    int carry = 0;
    int tmp = digits[digits.length - 1] + 1 + carry;
    list.addFirst(tmp % 10);
    carry = tmp / 10;
    for (int i = digits.length - 2 ; i >= 0 ; i --) {
        tmp = digits[i] + carry;
        list.addFirst(tmp % 10);
        carry = tmp / 10;
    }
    if (carry > 0) {
        list.addFirst(carry % 10);
    }
    // 确定终止的数组大小
    int[] arr = new int[list.size()];
    for (int i = 0 ; i < list.size() ; i ++) {
        arr[i] = list.get(i);
    }
    return arr;
}

如果嫌上面的思路做这道题太复杂,下面有一个更加聪明的解法。

public int[] plusOne(int[] digits) {
    int len = digits.length;
    for (int i = len - 1; i > -1; i--) {
        if (digits[i] == 9 ) { // 如果是9,改为0
            digits[i] = 0;
        } else { // 一旦数字不是9,则不会进位,直接返回即可
            digits[i] += 1;
            return digits;
        }
    }
    // 如果数组元素都是9,创建一个新的长度+1的数组,正好进位
    int[] newArray = new int[len + 1];
    newArray[0] = 1;
    return newArray;
}

67. 二进制求和 & 415. 字符串相加

分析

这两道题,只是进制的不同,解法是相同的。

public String addBinary(String a, String b) {
    StringBuilder sb = new StringBuilder();
    int m = a.length();
    int n = b.length();

    int i = m - 1, j = n - 1, carry = 0;
    while (i >= 0 || j >= 0) {
        int x = m - i < n - j ? 0 : Integer.valueOf(a.charAt(i) - '0');
        int y = m - i > n - j ? 0 : Integer.valueOf(b.charAt(j) - '0');
        int tmp = x + y + carry;
        sb.append(tmp % 2);  // 十进制改为 10 即可
        carry = tmp / 2;
        if (i == 0 && j == 0)
            break;
        if (i != 0) i --;
        if (j != 0) j --;
    }
    if (carry > 0) {
        sb.append(carry);
    }
    return sb.reverse().toString();
}

如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~

猜你喜欢

转载自blog.csdn.net/smartnijun/article/details/81740703