问题链接:
https://leetcode.com/problems/add-two-numbers/
https://leetcode.com/problems/add-two-numbers-ii/
https://leetcode.com/problems/add-to-array-form-of-integer/
这三个问题都是基于特殊数据结构的加法运算。需要注意整数int的范围和加法进位操作的表达。
问题一:基于链表存储的整数加法,数字从低位到高位依次存储在链表中,这是我的代码,有点丑陋,效率较低。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode p1=l1;
ListNode p2=l2;
int sign=0;
int temp=0;
ListNode r=new ListNode(1);
ListNode p3=r;
while(p1!=null || p2!=null)
{
if(p1==null)
p1=new ListNode(0);
if(p2==null)
p2=new ListNode(0);
temp=p1.val+p2.val+sign;
if(temp>=10)
{
sign=1;
temp-=10;
}
else
sign=0;
p3.next=new ListNode(temp);
if(p2.next==null && sign==1)
{
p3.next.next=new ListNode(1);
}
p3=p3.next;
p1=p1.next;
p2=p2.next;
}
return r.next;
}
}
Solutions里面的解法思路基本一致,但是处理的非常优雅:
有些tricks十分值得学习:虚拟头节点的加入,空节点统一处理为加上0。
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;
}
问题二:这个问题与第一问的区别是:数字从高位到低位依次存储在链表中,而链表的遍历只能从头到尾遍历,跟问题一一个解法,先上我捉急的代码:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null)
return l2;
if(l2==null)
return l1;
int len1=1,len2=1,temp=0;
ListNode p1=l1,p2=l2;
while(p1.next!=null)
{
p1=p1.next;
len1++;
}
while(p2.next!=null)
{
p2=p2.next;
len2++;
}
if(len1<len2)
{
p1=l2;
p2=l1;
temp=len1;
len1=len2;
len2=temp;
}
else
{
p1=l1;
p2=l2;
}
ListNode[] arr=new ListNode[len1+1];
arr[0]=new ListNode(0);
int i=1;
while(len1!=len2)
{
arr[i]=new ListNode(p1.val);
p1=p1.next;
len1--;
i++;
}
while(len1>0)
{
arr[i]=new ListNode(p1.val+p2.val);
i++;
p1=p1.next;
p2=p2.next;
len1--;
}
for(int j=arr.length-1;j>0;j--)
{
if(arr[j].val>=10)
{
arr[j-1].val+=1;
arr[j].val-=10;
}
}
if(arr[0].val!=0)
{
for(i=0;i<arr.length-1;i++)
{
arr[i].next=arr[i+1];
}
return arr[0];
}
else
{
for(i=1;i<arr.length-1;i++)
{
arr[i].next=arr[i+1];
}
return arr[1];
}
}
}
我的解法十分粗暴,因为是一年前刚开始刷LeetCode时写的,那时候有思路能AC就很不错了。更高效的处理方式是借助栈来从个位开始计算:
public class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> s1 = new Stack<Integer>();
Stack<Integer> s2 = new Stack<Integer>();
while(l1 != null) {
s1.push(l1.val);
l1 = l1.next;
};
while(l2 != null) {
s2.push(l2.val);
l2 = l2.next;
}
int sum = 0;
ListNode list = new ListNode(0);
while (!s1.empty() || !s2.empty()) {
if (!s1.empty()) sum += s1.pop();
if (!s2.empty()) sum += s2.pop();
list.val = sum % 10;
ListNode head = new ListNode(sum / 10);
head.next = list;
list = head;
sum /= 10;
}
return list.val == 0 ? list.next : list;
}
}
问题三:
思路一:在参加LeetCode contest遇到一道很脏的easy题目,边界条件处理起来比较痛苦(可能我没想到更好的方法,所以处理起来很暴力),代码如下:
class Solution {
public List<Integer> addToArrayForm(int[] A, int K) {
LinkedList<Integer> ret=new LinkedList<>();
boolean flag=false;
ArrayList<Integer> arr=new ArrayList<>();
while(K!=0)
{
arr.add(0,K%10);
K/=10;
}
int[] B=new int[arr.size()];
for(int i=0;i<arr.size();i++)
B[i]=arr.get(i);
if(A.length<B.length)
{
int[] tmp=B;
B=A;
A=tmp;
}
int j=A.length-1;
int k=B.length-1;
while(j>=0 && k>=0)
{
if(flag)
{
A[j] += B[k]+1;
flag=false;
}
else
A[j] += B[k];
if(A[j]>=10)
{
A[j]-=10;
flag=true;
}
k--;
j--;
}
while(j>=0)
{
if(flag)
{
A[j]+=1;
flag=false;
}
else
break;
if(A[j]>=10)
{
A[j]-=10;
flag=true;
}
j--;
}
if(flag)
ret.add(1);
for(int i:A)
ret.add(i);
return ret;
}
}
后来这个问题我看了Solutions觉得十分佩服,观察和思路都十分细腻,借鉴问题一的代码风格,该算法如下:
class Solution {
public List<Integer> addToArrayForm(int[] A, int K) {
LinkedList<Integer> ret=new LinkedList<>();
int i=A.length-1;
while(K!=0 || i>=0)
{
int p=i>=0?A[i]:0;
ret.add(0,(K+p)%10);
K=(K+p)/10;
i--;
}
return ret;
}
}
写出这样简洁的代码才让我感觉这是一道easy的问题,思路一的代码提交了5次才过也是没谁了。