1. 程式人生 > 其它 >連結串列+數學:實現兩個大數相加 ( Leetcode 02/67/371/445/989 )

連結串列+數學:實現兩個大數相加 ( Leetcode 02/67/371/445/989 )

節點程式碼

完整程式碼:

  <1> 連結串列實現程式碼

class ListNode {
 int val; // 資料域
 ListNode next; // 指標域,指向下⼀個節點
 ListNode() {
 }
 ListNode(int x) {
 val = x;
 }
}

  <2>存在 long 型別溢位的問題,需要⼿動測試

/**
 * 暴⼒解法:
 * 遍歷兩個連結串列使⽤數學思維分別將他們轉成整數
 * 對兩個整數進⾏求和得到sum
 * 將sum按照數學思維再轉成連結串列
 * ⼿動測試:
 * 若超過語⾔⽀持的資料類型範圍,則報錯
 * 解決辦法:BigInteger
 *
 *
 * 
@param l1 * @param l2 * @return */ public ListNode addTwoNumbers(ListNode l1, ListNode l2) { //把連結串列轉成數字,注意次序為逆序 long l1Value = 0; int digit = 0; while (l1 != null) { //該位對應的 單位 int pow = (int) Math.pow(10, digit); //在當前數值基礎上增加新的⼀個⾼位 l1Value += (long)l1.val * pow; digit++; //連結串列指向下⼀個節點 l1 = l1.next; }
long l2Value = 0; digit = 0; while (l2 != null) { //該位對應的 單位 int pow = (int) Math.pow(10, digit); //在當前數值基礎上增加新的⼀個⾼位 l2Value += (long)l2.val * pow; digit++; //連結串列指向下⼀個節點 l2 = l2.next; } //建立⼀個新連結串列,頭部為空節點 ListNode head = new ListNode(); ListNode cur = head; //數字相加 long sum = l1Value + l2Value; if
(sum == 0) { head = new ListNode(0); return head; } //數字再轉成連結串列 while (sum > 0) { //每次取當前最低位 int val = (int) (sum % 10); //移除最低位 sum = sum / 10; //建立新節點 ListNode node = new ListNode(val); //插⼊連結串列尾部 cur.next = node; //連結串列尾部指標移動 cur = cur.next; } return head.next; }

  <3>解決辦法:⽤ java.math.BigInteger 替代 long 型別。注意全類名寫法。

/**
* 暴⼒解法:存在的問題:使⽤long也會存在溢位
* 解決辦法:java.math.BigInteger
* 該類在leetcode預設環境沒有導⼊,所以使⽤全類名編寫
*
* @param l1
* @param l2
* @return
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
 //把連結串列轉成數字,注意次序為逆序
 java.math.BigInteger l1Value = java.math.BigInteger.valueOf(0);
 int digit = 0;
 while (l1 != null) {
 java.math.BigInteger carry =
java.math.BigInteger.valueOf(10).pow(digit);
 l1Value =
l1Value.add(carry.multiply(java.math.BigInteger.valueOf(l1.val)));
 digit++;
 l1 = l1.next;
 }
 java.math.BigInteger l2Value = java.math.BigInteger.valueOf(0);
 digit = 0;
 while (l2 != null) {
 java.math.BigInteger carry =
java.math.BigInteger.valueOf(10).pow(digit);
 l2Value =
l2Value.add(carry.multiply(java.math.BigInteger.valueOf(l2.val)));
 digit++;
 l2 = l2.next;
 }
 ListNode head = new ListNode();
 ListNode cur = head;
 //數字相加,然後再轉成連結串列
 java.math.BigInteger sum = l1Value.add(l2Value);
 if (sum.compareTo(java.math.BigInteger.valueOf(0)) == 0) {
 head = new ListNode(0);
 return head;
 }
 while (sum.compareTo(java.math.BigInteger.valueOf(0)) > 0) {
 int val = sum.mod(java.math.BigInteger.valueOf(10)).intValue();
 sum = sum.divide(java.math.BigInteger.valueOf(10));
 ListNode node = new ListNode((int) val);
 cur.next = node;
 cur = cur.next;
 }
 return head.next;
}

完整程式碼:

 /**
 * 最優解:數學思維解法
 * 1.遍歷兩個連結串列
 * 2.對應位置的節點數值相加
 * 3.將計算結果插⼊新連結串列尾部
 * ⼤於10,則進位,將進位加到下個節點
 *
 * 邊界問題
 * 兩個連結串列邊界:next==null
 * 細節問題
 * 兩個連結串列⻓度不⼀致,短連結串列⾼位視為0
 * 連結串列最⾼位發⽣進位,結果連結串列需要增加⼀個節點存放進位數字
 *
 * @param l1
 * @param l2
 * @return
 */
 public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
 ListNode p = l1, q = l2; // 原連結串列的兩個遍歷指標
 ListNode resultHead = new ListNode(-1); // 結果連結串列的頭結點head
 ListNode curr = resultHead; // 結果連結串列的遍歷指標,代表當前操作的節點
 int carry = 0; // 進位
 // 1.遍歷兩個連結串列
 while (p != null || q != null) { // 以⻓連結串列為準
 // 獲取當前節點的值:連結串列較短,已⽆節點,取0
 int x = p != null ? p.val : 0;
 int y = q != null ? q.val : 0;
 // 2.對應位置的節點數值相加
 int sum = x + y + carry;
 carry = sum / 10; // 如何得到進位:和對10求整,得到此次計算的進位
 int num = sum % 10; // 存放到新連結串列節點中的數值
 // 3.將計算結果插⼊新連結串列尾部
 curr.next = new ListNode(num); // 建立新節點
 curr = curr.next;
 p = p == null ? p : p.next;
 q = q == null ? q : q.next;
 }
 if (carry > 0) { // 處理進位節點
 curr.next = new ListNode(carry);
 }
 return resultHead.next;
}

測試用例

<1>輔助資料結構:連結串列。程式碼如下:

class ListNode {
 int val; // 資料域
 ListNode next; // 指標域,指向下⼀個節點
 ListNode() {
 }
 ListNode(int x) {
 val = x;
 }
}

<2>測試⽤例:

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

<3>測試程式碼:

public static void main(String[] args) {
 Solution solution=new AddTwoNumbers2().new Solution();
 int[] arr1 = {2, 4, 3};
 int[] arr2 = {5, 6, 4};
 ListNode l1 = new AddTwoNumbers2().new ListNode();
 ListNode l2 = new AddTwoNumbers2().new ListNode();
 ListNode l1Cur = l1;
 ListNode l2Cur = l2;
 for (int i = 0; i < arr1.length; i++) {
 ListNode node1 = new AddTwoNumbers2().new ListNode(arr1[i]);
 ListNode node2 = new AddTwoNumbers2().new ListNode(arr2[i]);
 l1Cur.next = node1;
 l1Cur = node1;
 l2Cur.next = node2;
 l2Cur = node2;
}
 ListNode result = solution.addTwoNumbers(l1.next, l2.next);
 while (result != null) {
 System.out.print(result.val + " "); // 輸出:7 0 8
 result = result.next;
 }
 }