1 题目:2.2.1 Add Two Numbers

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)

Output: 7 -> 0 -> 8

2 解决问题

看起来很简单的一道题目,但正好可以当成实例,学习一下如何将将题目变成最终正确、高效的代码。

2.1 问题定义

首先,第一步就是定义问题,确定好问题的域(problem domain)也就成功了一大半。例如,对于题目2.2.1:

Ø  确定输入很关键,输入是两个链表代表两个非负数,编码方式是:每个结点的值一个1位的数字,结点按逆序从个位到最高位排列。

Ø  输出很简单,就是返回一个链表,代表输入的两个链表的加和。

有了这些限定,我们就确定了要解决的问题是什么样子,有了方向才能进行下一步,从而不会跑偏。

2.2 设计算法

由于这道题目很明确,就是处理链表,所以就剩却了选取和设计数据结构这一步,我们就可以直接设计算法了。问题很简单,也不需要分治啊、动态规划啊什么的高级技术,老老实实的遍历两个链表就能解决问题了。

Algorithm addTwoNumbers(list1, list2)

       // Input:

       //            list1 and list2 representing 2 non-negative numbers

       //            Each node containing single digit

       //            All digits sorted in reversed order

       // Output:

       //           Result list representing the sum of list1 and list2

       //            in the same way of input list(single digit, reversed order)

       cur1 <- list1, cur2 <- list2

       carry <- 0, sum <- 0

 

       while cur1 != null or cur2 != null

       do

              if cur1 != null and cur2 != null

                     sum <- cur1 + cur2 + carry

              else if cur1 != null

                     sum <- cur1 + carry

              else

                     sum <- cur2 + carry

             

              result.addNewNode(sum % 10)

             

              carry <- sum / 10

              sum <- 0

 

              if cur1 != null do cur1 <- cur1.next

              if cur2 != null do cur2 <- cur2.next

       end

             

       if carry > 0

              result.addNewNode(carry)

 

       return result

2.3 分析算法

写好了伪代码,不管是在面试还是自己练习,我们可能都要问:“这设计的对吗?效率是多少啊?”所以,还不能急着写代码,先证明一下自己的算法确实正确,而且还很高效。本题的代码,或者说。这里只有sum是可以放在循环内的。

2) 终止条件:什么条件下可以继续循环,举个例子看看会不会出现off-by-one问题;

【本例】:因为只要有一个链表没到尾部,加法过程就要继续,所以循环条件就是cur1和cur2至少有一个不是null。

3) 循环体:循环体里应该做什么,有没有break, continue, return等其他改变循环顺序的出口,迭代使用变量是否每次都清0了;

【本例】:循环体里分三步1)加和;2)将sum的个位数添加到result尾部;3)处理进位,清空sum,准备下一轮迭代。

4) 计数器:计数器怎样累加,是否能每次迭代都变大或变小从而使循环正常终止,而不会造成死循环;

【本例】:在循环体最后,cur1和cur2不为空时,就向后移动,所以循环最终是能够终止的。因为没有使用for循环,所以这一部分代码也放在循环体里了。

5) 后处理:跳出循环后,需不需要进行一些遗留处理,使计算结果变完整,例如分页的最后一批数据。

【本例】:全部累积完毕退出循环后,也要考虑进位问题。

可以用断言和循环不变量严谨地证明正确性。同时也不难看出,算法的时间复杂度与list1和list2规模的较大者相关,较大者的长度决定了循环的次数。

2.4 实现代码

终于可以上手写代码了,这一步的重点是如何用好一种编程语言(C++)实现上面的算法。相比伪代码,在实现时我们要额外考虑:如何创建链表(用dummy header方法)、如何插入新结点等具体实现问题。这些问题都是容易出错的,所以不能掉以轻心!

2.5 层次设计和代码测试

在真实项目里,项目代码不可能只是一个实现了某个算法的函数这么简单。通过这些类或者函数只是小积木,写完之后我们还要累积成更大的积木。同时,在真实环境里,单元测试也是必不可少的。尽管上面已经证明了伪代码是正确且高效的,但只要不是最严谨的数学证明,代码就可能还是有小bug。而且,我们也免不了犯一些与算法无关,但与具体编程语言和操作系统环境有关错误,例如最低级的“==”比较,例如调用操作系统等外部API没进行异常处理等。所以测试是必不可少的,它能增强我们的信心。但在这里,这两个步骤就都省略了。

Leetcode解题-链表(2.2.1)AddTwoNumbers的更多相关文章

  1. Leetcode解题-链表(2.2.0)基础类

    1 基类的作用 在开始练习LeetCode链表部分的习题之前,首先创建好一个Solution基类,其作用就是: Ø  规定好每个子Solution都要实现纯虚函数test做测试: Ø  提供了List ...

  2. Leetcode解题-链表(2.2.6)RotateList

    1 题目:Rotate List Given a list, rotate the list to the right by k places, where k is non-negative. Fo ...

  3. Leetcode解题-链表(2.2.3)PartitionList

    题目:2.2.3 Partition List Given a linked list and a value x, partition it such that all nodes less tha ...

  4. Leetcode解题-链表(2.2.2)ReverseLinkedList

    题目:2.2.2 Reverse Linked List II Reverse a linked list from position m to n. Do it in-place and in on ...

  5. Leetcode解题思想总结篇:双指针

    Leetcode解题思想总结篇:双指针 1概念 双指针:快慢指针. 快指针在每一步走的步长要比慢指针一步走的步长要多.快指针通常的步速是慢指针的2倍. 在循环中的指针移动通常为: faster = f ...

  6. LeetCode解题报告:Linked List Cycle && Linked List Cycle II

    LeetCode解题报告:Linked List Cycle && Linked List Cycle II 1题目 Linked List Cycle Given a linked ...

  7. LeetCode 单链表专题 (一)

    目录 LeetCode 单链表专题 <c++> \([2]\) Add Two Numbers \([92]\) Reverse Linked List II \([86]\) Parti ...

  8. 【算法题 14 LeetCode 147 链表的插入排序】

    算法题 14 LeetCode 147 链表的插入排序: 解题代码: # Definition for singly-linked list. # class ListNode(object): # ...

  9. leetcode解题报告(2):Remove Duplicates from Sorted ArrayII

    描述 Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For ex ...

随机推荐

  1. [HDU 3507]Print Article

    Description Zero has an old printer that doesn't work well sometimes. As it is antique, he still lik ...

  2. [HNOI2002]彩票

    题目描述 某地发行一套彩票.彩票上写有1到M这M个自然数.彩民可以在这M个数中任意选取N个不同的数打圈.每个彩民只能买一张彩票,不同的彩民的彩票上的选择不同. 每次抽奖将抽出两个自然数X和Y.如果某人 ...

  3. Passward

    问题 A: Passward 时间限制: 1 Sec  内存限制: 512 MB 题目描述 你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s. 传说打开庙门的密码是这个字符串的一个子串 t,并 ...

  4. codeforces round #419 B. Karen and Coffee

    To stay woke and attentive during classes, Karen needs some coffee! Karen, a coffee aficionado, want ...

  5. NOIP2014-6-14模拟赛

    Problem 1 抓牛(catchcow.cpp/c/pas) [题目描述] 农夫约翰被通知,他的一只奶牛逃逸了!所以他决定,马上出发,尽快把那只奶牛抓回来. 他们都站在数轴上.约翰在N(O≤N≤1 ...

  6. poj 1704 Georgia and Bob(阶梯博弈)

    Georgia and Bob Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9363   Accepted: 3055 D ...

  7. SpringCloud学习之Hystrix

    一.为什么要有断路器 在分布式系统当中,服务之间调用关系会随着业务的发展而变的复杂,一个服务可能依赖多个服务,服务之间层层依赖也是家常便饭的事情,如果一个服务的瘫痪很有可能导致整个系统的崩溃.比如说, ...

  8. mooc- 基本程序设计方法week1,week2

    学习了第一单元我们几本可以写出10行左右的代码. week1:python编程之基本方法 1.从计算机到程序设计语言: 理解计算机:计算机是能够根据一组指令操作数据的机器. 功能性:可以进行数据计算 ...

  9. Spring AOP @Around @Before @After 区别

    此段小代码演示了spring aop中@Around @Before @After三个注解的区别@Before是在所拦截方法执行之前执行一段逻辑.@After 是在所拦截方法执行之后执行一段逻辑.@A ...

  10. log4j不生成日志文件的问题

    直接看我的注解吧 注意地址的斜杠,还有地址别写什么相对地址了,这包太老了,服务器update一下兼容问题就出来了. #第一个参数定义达到什么程度就输出 第二第三....第N 定义输出的类型 #debu ...