連結串列+數學:實現兩個大數相加 ( Leetcode 02/67/371/445/989 )
阿新 • • 發佈:2021-07-21
節點程式碼
完整程式碼:
<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; } }