LeetCode 2.Add Two Numbers 两数相加 Python3 三种解法

LeetCode 2.Add Two Numbers 两数相加 Python3 三种解法

  • LeetCode 2.Add Two Numbers 两数相加 Python3 三种解法
    • 链表基础
    • 官网答案
    • 官网答案Python版本
    • 官网答案解答细节
    • 链表暴力还原
    • 递归法

LeetCode 2.Add Two Numbers 两数相加 Python3 三种解法

链表基础

由于做提前连链表是怎么实现的都不知道所以补了点课。
Single Linked List 代码来自这位兄台
pasilo
https://blog.51cto.com/13047263/2070815
内容理解我看的知乎,但是其实我都还没有独立实现一个python链表,深浅拷贝啥的很晕。做这个题简直坐飞机。
如何更好的理解链表

以下代码和LeetCode上面的链表稍微有些许不同,那个里面链表和链表上面的节点是相同的类。而这边抽象出了链表节点和链表本身两个类。毕竟这段代码实现了更多链表方法。单用一个Node类不太容易做到了。需要注意的就是实现层面current是一个节点类的指针,指示当前的Node最终就是尾部,head也是一个节点类的指针,指示头部Node。

lass Node {
    private int val; // node value
    private Node next; // next node location

    public Node() {
    }

    // constructor to construct node value and next node RAM location
    public Node(int data) {
        this.val = data;
        this.next = new Node();
    }

    public int getData() {
        return this.val;
    }

    // change data value
    public void setData(int value) {
        this.val = value;
    }

    // get next node location
    public Node getNext() {
        return this.next;
    }

    // generate new node with new value
    public void setNewNext(int value) {
        // Node newNode = new Node(value);
        this.next = new Node(value);
    }

    // set next node with a generated node instance
    public void setNext(Node node) {
        this.next = node;
    }
}

public class SingleLinkedList {

    private Node head;
    private Node current;

    // current is a pointer for node
    // set head node with value
    // set head node with location of next node
    public SingleLinkedList(int data) {
        this.head = new Node(data);
        current = head;
    }

    // set next node with value
    // set next node with location of next node
    public void append(int value) {
        current.setNewNext(value);
        current = current.getNext();
    }

    public void remove(int destation) {
        Node pointer = this.head;
        for (int i = 0; i < destation - 1; i++) {
            pointer = pointer.getNext();
        }
        // jump over node at the position of destation
        Node temp = pointer.getNext().getNext();
        pointer.setNext(temp);
    }

    public void insert(int destation, int value) {
        Node pointer = this.head;
        for (int i = 0; i < destation - 1; i++) {
            pointer = pointer.getNext();
        }
        Node temp = pointer.getNext();
        Node newNode = new Node(value);
        pointer.setNext(newNode);
        newNode.setNext(temp);
    }

    // get the value of node at locatio
    public int at(int index) {
        Node pointer = this.head;
        for (int i = 0; i < index; i++) {
            pointer = pointer.getNext();
        }
        return pointer.getData();
    }

    // print out the linked data
    public void display() {
        Node pointer = this.head;
        // pointer move from head to the tail
        // current is the tail node
        while (current != pointer) {
            System.out.printf("%d->", pointer.getData());
            pointer = pointer.getNext();
        }
        System.out.println(pointer.getData());
        System.out.println("this is the end.\n");
    }

    public int size() {
        int size = 1;
        Node pointer = this.head;
        while (current != pointer) {
            pointer = pointer.getNext();
            size++;
        }
        return size;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SingleLinkedList l1 = new SingleLinkedList(0);
        l1.append(1);
        l1.display();

        SingleLinkedList l2 = new SingleLinkedList(0);
        l2.append(1);
        l2.append(2);
        l2.display();

    }
}

官网答案

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode dummyHead = new ListNode(0);
    ListNode p = l1, q = l2, curr = dummyHead;
    int carry = 0;
    while (p != null || q != null) {
        int x = (p != null) ? p.val : 0;
        int y = (q != null) ? q.val : 0;
        int sum = carry + x + y;
        carry = sum / 10;
        curr.next = new ListNode(sum % 10);
        curr = curr.next;
        if (p != null) p = p.next;
        if (q != null) q = q.next;
    }
    if (carry > 0) {
        curr.next = new ListNode(carry);
    }
    return dummyHead.next;
}

https://leetcode-cn.com/problems/two-sum/solution/liang-shu-xiang-jia-by-

官网答案Python版本

def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        head = ListNode(0)
        # curr is the dummy linked list
        curr = head
        carry = 0
        while l1 or l2:
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0
            
            sum = x + y + carry
            carry = sum // 10
            curr.next = ListNode(sum % 10)
            # pointer move to the next node
            curr =  curr.next
            
            
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        # finally there need to carry
        if (carry > 0):
            curr.next = ListNode(1)
        return head.next

官网答案解答细节

稍微改改就能实现一个python化的版本。但是老实说就算是改写,这里面也太容易出错了因为细节实在是太多了。代码虽然短但是里面琐碎的细节真心多。

  1. 哑节点 head 指示链表头ListNode, curr指示当前ListNode, carry记录进位
head = ListNode(0)
# 注意这个哑节点的值根本就不会被用到,next才开始记录两数之和
curr = head
carry = 0
  1. l2和l1可能长度不同,一个结束后另一个补位0
while l1 or l2:
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0
  1. 这段细节比较多
    1. sum 必须用变量来表示, 给节点ListNode赋值。
    2. 另外注意while iteration中第一次使用模运算得到哑节点next的位置和值的时候,这个值和位置才是真正的结果链表的起点。
    3. carry表示进位,注意这一次生成的carry会默认参与下一次的sum运算,也就是其实进位已经靠着结构而不是操作达成。(awesome!)
    4. 当前结点位移到新生成的结点。
sum = x + y + carry
carry = sum // 10
curr.next = ListNode(sum % 10)
curr =  curr.next
  1. 结束这一轮全局位置的运算,结点向后位移一个位置。如过链表循环已经结束步骤2会帮助补位置。
if l1:l1 = l1.next
if l2:l2 = l2.next

5.注意最后一轮运算后我们的通过sum运算进位的机制没有了,所以需要手动进位下。最后的答案是哑结点指向的结点

if (carry > 0):
	curr.next = ListNode(1)
return head.next

链表暴力还原

暴力求解
原方法地址 https://blog.csdn.net/fuxuemingzhu/article/details/79379626

  1. 将链表还原为数字
    1. 需要字符串
    2. 字符串翻转,转数字
  2. 数字相加
  3. 得到的值上的每个位置元素回填链表
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        num1 = ''
        num2 = ''
        while l1:
            num1 += str(l1.val)
            l1 = l1.next
        while l2:
            num2 += str(l2.val)
            l2 = l2.next
        add = str(int(num1[::-1]) + int(num2[::-1]))[::-1]
        head = ListNode(add[0])
        answer = head
        for i in range(1, len(add)):
            node = ListNode(add[i])
            head.next = node
            head = head.next
        return answer

递归法

这个解太妙了,同时解决进位和补位问题,但是python递归好麻烦。addTwoNumbers不能递归自己。平白无故多了几个步骤。

class Solution:
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        def addIter(l1, l2):
            if not l1: return l2
            if not l2: return l1

            sum = l1.val + l2.val  
            res = ListNode(sum % 10)
            res.next = addIter(l1.next, l2.next)
           
            if sum >= 10:
                res.next = addIter(res.next, ListNode(1))
            return res
        res = addIter(l1,l2)
        return res
            

再来看看楼上那位的C++版本,明显优秀一些。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        if (!l1) return l2;
        if (!l2) return l1;
        int target = l1->val + l2->val;
        ListNode* res = new ListNode(target % 10);
        res->next = addTwoNumbers(l1->next, l2->next);
        if (target >= 10)
            res->next = addTwoNumbers(res->next, new ListNode(1));
        delete l1, l2;
        return res;
    }
};

你可能感兴趣的:(LeetCode,Java,python,Linked,List,Raw,Code,algorithm)