2.两数之和

作者: Sun东辉 | 来源:发表于2022-04-22 07:43 被阅读0次

    使用两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。即每个数字位的值都是有效的,例如 60 不会表示为 060。

    解题思路:链表求和

    这里首先想到的,是将链表转换成具体的数字,相加,再将具体的数字转换为链表,具体的实现如下:

    type ListNode struct {
        Val  int
        Next *ListNode
    }
    
    func AddTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
        v1 := getValue(l1)
        v2 := getValue(l2)
        s := v1 + v2
        return makeNode(s)
    }
    
    func getValue(node *ListNode) int {
        v := 0
        base := 0
        for {
            vb := math.Pow10(base)
            v += node.Val * int(vb)
            base++
            if node.Next == nil {
                break
            }
            node = node.Next
        }
        return v
    }
    
    func makeNode(v int) *ListNode {
        list := make([]int, 0)
        for {
            rem := v % 10
            list = append(list, rem)
            if v < 10 {
                break
            }
            v = (v - rem) / 10
        }
    
        if len(list) == 0 {
            return nil
        }
        res := &ListNode{
            Val: list[0],
        }
        temp := res
        for i := 1; i < len(list); i++ {
            temp.Next = &ListNode{Val: list[i]}
            temp = temp.Next
        }
        return res
    }
    
    

    在一定范围内,这样的实现是可行的,而且在我看来,这样实现最大的好处是直观,但显然 LeetCode 不这样认为!

    数字直接相加走不通,那么,还是直接链表相加吧,这里要考虑进位的问题,代码实现如下:

    func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
        carry, head := 0, l1
        for {
            // 值相加再加进位
            l1.Val += l2.Val + carry
            // 进位
            carry = l1.Val / 10
            // 求余
            l1.Val %= 10
            if l2.Next == nil {
                break
            } else if l1.Next == nil {
                // 将 l2 的链表阶段接到 l1 上
                l1.Next = l2.Next
                break
            }
            // 执行链表中的下一项
            l1 = l1.Next
            l2 = l2.Next
        }
    
        // 如果前面的进位没有用到
        for carry != 0 {
            if l1.Next == nil {
                l1.Next = &ListNode{0, nil}
            }
            l1.Next.Val += carry
            carry = l1.Next.Val / 10
            l1.Next.Val %= 10
            l1 = l1.Next
        }
    
        return head
    }
    
    

    既然链表可以实现,那么直接用数组呢?

    // 数组转换为链表
    func makeNodeByList(list []int) *ListNode {
        if len(list) == 0 {
            return nil
        }
        res := &ListNode{
            Val: list[0],
        }
        temp := res
        for i := 1; i < len(list); i++ {
            temp.Next = &ListNode{Val: list[i]}
            temp = temp.Next
        }
        return res
    }
    
    // 链表转换为数组
    func nodeToList(node *ListNode) []int {
        r := make([]int, 0)
        for {
            if node == nil {
                break
            }
            r = append(r, node.Val)
            node = node.Next
        }
        return r
    }
    
    // 数组相加
    func addTwoList(l1, l2 []int) []int {
        minList := l1
        maxList := l2
        if len(l1) > len(l2) {
            minList = l2
            maxList = l1
        }
        r := maxList
        for i := range minList {
            r[i] = maxList[i] + minList[i]
        }
        for i, v := range r {
            if v >= 10 {
                r[i] -= 10
                if i < len(r)-1 {
                    r[i+1]++
                } else {
                    r = append(r, 1)
                }
            }
        }
        return r
    }
    
    // 这里返回结果
    func addTwoNumsList(l1 *ListNode, l2 *ListNode) *ListNode {
        list1 := nodeToList(l1)
        list2 := nodeToList(l2)
        list := addTwoList(list1, list2)
        return makeNodeByList(list)
    }
    
    

    事实证明,虽然链表的空间占用率较小,但是数组的时间复杂度更低,至少 LeetCode 是这样认为的。

    最后贴一张数组运行的结果图。


    下一题传送门

    相关文章

      网友评论

        本文标题:2.两数之和

        本文链接:https://www.haomeiwen.com/subject/sjziertx.html