Target Sum Subarray
March 19, 2019
Our solution finds the subarray in a single scan by keeping two pointers, lo
and hi
, and the sum
between them, incrementing hi
when sum
is less than the target
, incrementing lo
when sum
is greater than the target
, and returning when sum
is equal to the target
; it fails when it reaches the end of the array without finding the target
:
(define (subarray vec target) (let loop ((lo 0) (hi 1) (sum (vector-ref vec 0))) (display lo) (display " ") (display hi) (display " ") (display sum) (display " ") (display (subvec vec lo hi)) (newline) (cond ((= target sum) (list lo hi)) ((< target sum) (loop (+ lo 1) hi (- sum (vector-ref vec lo)))) ((= hi (vector-length vec)) #f) (else (loop lo (+ hi 1) (+ sum (vector-ref vec hi)))))))
Here hi
is the next element past the end of the current subarray, which is more convenient. The only trick is arranging the cond
clauses in the right order. Here are the example problems, with debugging output enabled so you can see what is happening:
> (subarray '#(1 4) 3) 0 1 1 #(1) 0 2 5 #(1 4) 1 2 4 #(4) 2 2 0 #() #f > (subarray '#(1 4 0 0 3 10 5) 7) 0 1 1 #(1) 0 2 5 #(1 4) 0 3 5 #(1 4 0) 0 4 5 #(1 4 0 0) 0 5 8 #(1 4 0 0 3) 1 5 7 #(4 0 0 3) (1 5) > (subarray '#(1 4 20 3 10 5) 33) 0 1 1 #(1) 0 2 5 #(1 4) 0 3 25 #(1 4 20) 0 4 28 #(1 4 20 3) 0 5 38 #(1 4 20 3 10) 1 5 37 #(4 20 3 10) 2 5 33 #(20 3 10) (2 5) > (subarray '#(1 4 20 3 10) 33) 0 1 1 #(1) 0 2 5 #(1 4) 0 3 25 #(1 4 20) 0 4 28 #(1 4 20 3) 0 5 38 #(1 4 20 3 10) 1 5 37 #(4 20 3 10) 2 5 33 #(20 3 10) (2 5)
You can run the program at https://ideone.com/6djybl.
In Python.
This one is beautifully built for perl – a little bit of golf here..
Without the comments and stricture….
Here’s a solution in C.
Example Usage:
Here’s a Haskell version that works for negative numbers and non-integers as well. It uses a map to keep track of the cumulative sum of the elements so that it can make a single pass through the list. (It trades time for space.) Note that Haskell has a particular way of printing rational numbers: 2/5 is 2 % 5, -1/3 is (-1) % 3, etc.