zoukankan      html  css  js  c++  java
  • leetcode算法:2.两数相加

    两数相加

    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

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

    示例:

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

    思考

    这题比较方便的是给定的两个链表已经是从个位开始的,不需要我们再去找到最低位。 有两个需要注意的地方:

    • 第一个是长短不一的链表是要一直处理到最长那个结束的,而不是最短链表
    • 第二个需要注意的地方是最高位之和可能会导致进位,此时可能需要新增一个节点,如 753+864 中 7+8导致的进位

    解答

    • 时间复杂度: O(max(list1, list2)),因为处理的次数取决于最长的那个链表
    • 空间复杂度: O(max(list1, list2)),新列表的长度最多为max(list1, list2)+1,因为最高位可能导致进位
    package algo
    
    type ListNode struct {
    	Val  int
    	Next *ListNode
    }
    
    func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
    	// 存在一个空list时无意义
    	if l1 == nil || l2 == nil {
    		return nil
    	}
    
    	var (
    		sumList     = &ListNode{}
    		currentNode = sumList
    		nextL1      = l1
    		nextL2      = l2
    		carry       = 0 //进位值
    	)
    
    	for nextL1 != nil || nextL2 != nil {
    		var sum, x, y int
    
    		if nextL1 != nil {
    			x = nextL1.Val
    			nextL1 = nextL1.Next
    		} else {
    			x = 0
    		}
    
    		if nextL2 != nil {
    			y = nextL2.Val
    			nextL2 = nextL2.Next
    		} else {
    			y = 0
    		}
    
    		sum = x + y + carry
    		carry = sum / 10
    
    		// 不要使用 currentNode.Val = sum % 10; currentNode.Next = &ListNode{};
    		// 否则会导致最后多余一个ListNode{}结点
    		currentNode.Next = &ListNode{Val: sum % 10}
    		currentNode = currentNode.Next
    
    	}
    
    	// 最高位相加导致的进位,如 753+864 中 7+8导致的进位
    	if carry > 0 {
    		currentNode.Next = &ListNode{Val: carry}
    	}
    
    	return sumList.Next
    }
    

      

    单元测试:

    package algo
    
    import (
    	"math/rand"
    	"strings"
    	"testing"
    )
    
    func TestTwoNumbers(t *testing.T) {
    	linkList1 := makeList()
    	linkList2 := makeList()
    
    	res := addTwoNumbers(linkList1, linkList2)
    	if res == nil {
    		t.Fatal("empty result")
    	}
    
    	print("第一链表: ")
    	traverse(linkList1)
    
    	print("第二链表: ")
    	traverse(linkList2)
    
    	print("结果链表: ")
    	traverse(res)
    
    	println(strings.Repeat("=", 30))
    
    	sameList := makeList()
    	res = addTwoNumbers(sameList, sameList)
    	if res == nil {
    		t.Fatal("empty result")
    	}
    
    	print("同一链表: ")
    	traverse(sameList)
    
    	print("结果链表: ")
    	traverse(res)
    }
    
    // 创建单链表
    func makeList() *ListNode {
    	var listNode = &ListNode{Val: rand.Intn(9) + 1}
    	cnt := rand.Intn(6) + 3
    	for i := 1; i < cnt; i++ {
    		l := listNode
    		for {
    			if l.Next == nil {
    				l.Next = &ListNode{Val: rand.Intn(9) + 1}
    				break
    			}
    			l = l.Next
    		}
    	}
    	return listNode
    }
    
    // 遍历单链表
    func traverse(linkList *ListNode) {
    	iter := linkList
    	for {
    		if iter != nil {
    			if iter.Next == nil {
    				print(iter.Val)
    			} else {
    				print(iter.Val, "->")
    			}
    			iter = iter.Next
    		} else {
    			break
    		}
    	}
    	println()
    }
    

      

  • 相关阅读:
    网易2019校招C++研发工程师笔试编程题
    牛客网 数串
    ps aux 状态介绍
    阿里在线测评解析
    Ubuntu 18.04安装 Sublime
    file '/grub/i386-pc/normal.mod' not found.解决方案
    解决Windows10与Ubuntu系统时间不一致问题
    进程与线程的区别
    大端模式和小端模式
    2016湖南省赛----G
  • 原文地址:https://www.cnblogs.com/pluse/p/13308346.html
Copyright © 2011-2022 走看看