views:

596

answers:

6

Hello,

I was trying to write a program for the problem I mentioned above, the numbers (i.e the lists) can be of unequal length, I was not able to figure out a way to do this other than the most commonly thought of approach i.e

  1. reverse list-1
  2. reverse list-2
  3. find the sum and store it in a new list represented by list-3
  4. reverse the list.

The complexity of this should be of the O(n+m). Is there anyway to reduce it, or do it better?

+3  A: 

Ideally the first thing I would do is store the numbers in reverse digit order, so 43,712 is stored as:

2 -> 1 -> 7 -> 3 -> 4

It makes arithmetic operations much easier.

Displaying a number can be done either iteratively or more simply with a recursive algorithm. Note: all this assumes singly-linked lists.

Edit: But you've since stated you have no choice in the storage format. As such, your best bet is to reverse both the lists, do the addition and then reverse the result.

cletus
I am assuming that he doesn't get to pick how they are stored, which is why he starts with reversing the list, otherwise yours is the simplest approach.
James Black
yup thats right James
Shiv
But what about the time it takes to reverse them, since you don't know the length ahead of time, so you can't do it in place. You end up removing the head of the source, and pushing them back into the other order, but that means you fully traverse the list twice, doing a minor operation.
James Black
Traversing a list twice is still an O(n) operation. Other approaches end up just copying the list anyway (eg if you push nodes onto a stack to de facto reverse them) or if you recursively walk backwards that's actually an O(n^2) operation.
cletus
+1  A: 

If you can use a doubly-linked list then you can quickly traverse to the end of each list, and then just work your way back, adding the numbers at each point and add that to a new list.

You will need to determine which list is longer, and add up based on the length of the shorter list, and then just finish summing and adding the longer list.

But, you will have some issues with the fact that the sum may go over one digit, so if that happens you will need to keep track of the overflow and add that to the next node.

James Black
im using only a singly linked list.
Shiv
Then determine the length, find the longest, add the nodes that are in excess to the new list, then go through adding them, but, you need to keep track of the earlier node in case of overflow, and if that overflow overflows, then you have a problem.
James Black
That will involve traversing the list multiple times, first to find the lengths, and then to do additions, I am trying to however minimize the number of times I traverse the list. Thanks for your suggestion though, I had thought of that initially.
Shiv
@Shiv - It is only traversing twice, the first time is fast in that you just count the nodes in each list, and the second will involve math and adding new nodes. Reversing the list will be more expensive as you are creating a new list since you can't just swap in-place, since you don't know the end, and have a singly linked list.
James Black
@James - you can reverse a linked list without allocating new objects.
Stephen C
@Stephen - When reversing you can take the first node, put it as the head of the new list and then have the second point to the head of the new list (so the node just added is the head), which is fast, but you are reversing twice, so traversing the list three times, each time doing an operation, albeit a fast one, but it would be quicker if you knew the end and had a double linked list, as you could just be swapping two nodes in each iteration.
James Black
+1  A: 

I don't think of a better solution to the problem as stated. The root problem is that you have to process the list elements in the reverse order. In theory you could implement the algorithm recursively, avoiding the need for explicit reversal steps. But that requires O(max(m,n)) stack space, and would most likely be slower.

But I think that is really saying that you've chosen a poor representation. If you represent the numbers as doubly linked lists of int or arrays of int (with an explicit size), the complexity will be O(max(m,n)) with a smaller constant of proportionality.

Note: O(max(m,n)) and O(m+n) are both abuses of O notation. Strictly speaking, O is a defined in terms of a limit as a single variable goes to infinity. Looked at it this way, O(max(m,n)) and O(m+n) both reduce to O(m) or O(n). However, I understand what you are trying to say :-).

Stephen C
well thats a design constraint, im not at liberty to choose the method of representation, its something that came up in a discussion with a friend a few hours ago.:)
Shiv
A: 

The only potential optimization, which would come at the cost of some code clarity, would be to combine the initial reversals into a single loop. You then go from O(n+m+m) to O(m+m), although the steps inside the loop are costlier.

jfawcett
@jfawcett - I'm pretty sure this would give no improvement ... assuming that you are doing list reversal by pointer reversal.
Stephen C
@jfawcett, can you explain your solution a little more, i thought along these lines but was at loss to see how I could combine the initial steps of reversing both the lists in a single loop. since I dont know which number is longer, maybe some pseudocode would help.
Shiv
The method you proposed was reverse/count 1 (len=x), then reverse/count 2 (len=y), then sum/store the new (len=max(x,y)). If, instead, you have a single loop that reverses both 1 and 2 at the same time. When reversing a single, you do something like while( currentHead != NULL ) { <reverse> }Replace this with while( currentHead1 != NULL || currentHead2 != NULL) { if (currentHead1) { reverse 1 } if (currentHead2) { reverse 2 } }This only works with non-recursive reversal, of course.
jfawcett
+1  A: 

You can do better without list reversal. WLOG I'll assume that both lists have equal length (prepend with 0 if necessary).

Start the addition from left to right (from most significant to least significant digit). You have three cases, depending of the sum of two digits:

  1. = 9: keep the nine and increase a counter
  2. < 9: write counter x nine, write sum, reset counter
  3. > 9: increase last digit, write counter x zero, write sum (modulo 10), reset counter

I'll work on the following example:

2 568 794 +
1 438 204
--------- =
4 006 998
  1. Add 2 + 1 = 3: case 3.
    • list = (3), counter = 0
  2. Add 5 + 4 = 9: case 1
    • list = (3), counter = 1
  3. Add 6 + 4 = 9: case 1
    • list = (3), counter = 2
  4. Add 8 + 8 = 16: case 3
    • list = (4, 0, 0, 6), counter = 0
  5. Add 7 + 2 = 9: case 1
    • list = (4, 0, 0, 6), counter = 1
  6. Add 9 + 0 = 9: case 1
    • list = (4, 0, 0, 6), counter = 2
  7. Add 4 + 4 = 8: case 2
    • list = (4, 0, 0, 6, 9, 9, 8), counter = 0
Alexandru
Thats great, but how will this method work for unequal length lists?
Shiv
You still need to know the sizes of the list and make them the equal by prepending 0 to the shorter (or, put the first m - n elements (m > n) in the final list).
Alexandru
A: 

can u explain it in bit detail. I am confused at first step u say 2+1 =3 so write counter x nine, write sum, reset counter so two values will be written into list but only sum is written not counter x nine. Same confusion occurs at step 3. In algo only 2 values are to be written but in the list 3 values have been written that are 0,0,6.

Ankuj