2

Suppose I have an array lets say [1,2,3,4]:

I want to find the sum as follows:

First I generate pairs like:

(1 2 3 4)

(123)(4)

(1)(234)

(12)(34)

(12)(3)(4)

(1)(23)(4)

(1)(2)(34)

(1)(2)(3)(4)

The ans would then be sum of elements in one group multiplied by the length of that group(for all possible groups)

eg in the arrangement (123)(4), the sum would be

(1+2+3)*3 + (4)*1

I just want the final sum which is sum of all such values , not the actual groups. How can I do this?

I was able to do it by first generating all possible groups and then finding the sum

But since I only need the sum and not the actual groups, is there a better way?

humble
  • 2,016
  • 4
  • 27
  • 36
  • http://stackoverflow.com/questions/22915726/return-all-possible-combinations-of-a-string-when-splitted-into-n-strings would be relevant here. I doubt this can be done in O(N) time though. – Martijn Pieters Sep 26 '16 at 11:28
  • There might be a possibility, but it depends on whether your array is fixed for the problem (in terms of amount of elements in it) or if you want to build a function for arbitrary arrays. Which is the case? – Draugr Sep 26 '16 at 12:17
  • I am not sure that I quite understand what you mean .... In the question we would be given an array ( of any length ) and its elements and would be required to find the sum as mentioned – humble Sep 26 '16 at 12:37
  • Ok, then my idea won't work if it could have any length. – Draugr Sep 26 '16 at 12:56
  • Can you still tell your idea in comments please – humble Sep 26 '16 at 12:58
  • The number of sums is 2**(len(L)-1). A list of 8 elements produce 128 different arrangements. It is an exponential problem. You either generate all possible solutions and then calculate each answer, or you calculate each answer on the fly. Either way it is still exp. – vz0 Sep 26 '16 at 12:59
  • Basically to expand the term for a fixed array length, then sort and arrange the additions and multiplications manually in a way to optimise the amount and order. This could have helped to optimise runtime for one specific case, but won't help for your actual problem, see vz0's reasoning. – Draugr Sep 26 '16 at 13:13

1 Answers1

1

The number of arrangements is 2**(len(L)-1). A list of 8 elements produce 128 different arrangements. It is an exponential problem. You either generate all possible solutions and then calculate each answer, or you calculate each answer on the fly. Either way it is still exp.

def part1(L, start, lsum):
    if start == len(L):
        print lsum
    else:
        for i in range(start, len(L)):
            left = sum(L[start:i+1]) * (i-start+1)
            part1(L, i + 1, lsum + left)

def part2(L, M, X, start):
    if start == len(L):
        M.append(X)
        print sum([sum(x) * len(x) for x in X])
    else:
        for i in range(start, len(L)):
            part2(L, M, X + [L[start:i+1]], i + 1)

ex:

>>> part1(L, 0, 0)
10
17
15
28
13
20
22
40
>>> M = []
>>> part2(L, M, [], 0)
10
17
15
28
13
20
22
40

edit: sum of all the sums in O(n**3)

for L = [1,2,3,4,5,6]

[[[1],                  [2],            [3],            [4],            [5],            [6]],
 [[1],                  [2],            [3],            [4],            [5, 6]],
 [[1],                  [2],            [3],            [4, 5],                         [6]],
 [[1],                  [2],            [3],            [4, 5, 6]],
 [[1],                  [2],            [3, 4],                         [5],            [6]],
 [[1],                  [2],            [3, 4],                         [5, 6]],
 [[1],                  [2],            [3, 4, 5],                                      [6]],
 [[1],                  [2],            [3, 4, 5, 6]],
 [[1],                  [2, 3],                         [4],            [5],            [6]],
 [[1],                  [2, 3],                         [4],            [5, 6]],
 [[1],                  [2, 3],                         [4, 5],                         [6]],
 [[1],                  [2, 3],                         [4, 5, 6]],
 [[1],                  [2, 3, 4],                                      [5],            [6]],
 [[1],                  [2, 3, 4],                                      [5, 6]],
 [[1],                  [2, 3, 4, 5],                                                   [6]],
 [[1],                  [2, 3, 4, 5, 6]],
 [[1, 2],                               [3],            [4],            [5],            [6]],
 [[1, 2],                               [3],            [4],            [5, 6]],
 [[1, 2],                               [3],            [4, 5],                         [6]],
 [[1, 2],                               [3],            [4, 5, 6]],
 [[1, 2],                               [3, 4],                         [5],            [6]],
 [[1, 2],                               [3, 4],                         [5, 6]],
 [[1, 2],                               [3, 4, 5],                                      [6]],
 [[1, 2],                               [3, 4, 5, 6]],
 [[1, 2, 3],                                            [4],            [5],            [6]],
 [[1, 2, 3],                                            [4],            [5, 6]],
 [[1, 2, 3],                                            [4, 5],                         [6]],
 [[1, 2, 3],                                            [4, 5, 6]],
 [[1, 2, 3, 4],                                                         [5],            [6]],
 [[1, 2, 3, 4],                                                         [5, 6]],
 [[1, 2, 3, 4, 5],                                                                      [6]],
 [[1, 2, 3, 4, 5, 6]]]

There seems to be a pattern. The odd case is: the sets having the first elements of the sequence as the smallest element as the sorted set, there are 32. But then all the rest there are 16. For each element of the list, I add all the sets which contains that element as the first sorted element.

def part3(L):
    ret = 0
    for i in range(len(L)):
        p = 0
        for k in range(len(L) - i - 1):
            p += sum(L[i:i+k+1]) * (k+1) * 2**(len(L) - i - k - 2)
        p += sum(L[i:]) * (len(L) - i)
        ret += p * max(1, 2**(i-1))
    return ret

edit2: to lower it to O(n^2) you need to use DP. building a table of sums to calculate each sum in O(1). You build an array S with S[i] = S[i-1] + L[i] and sum(L[a:b]) is S[b] - S[a].

vz0
  • 32,345
  • 7
  • 44
  • 77
  • i just want the final sum which is sum of all possible groups' sum – humble Sep 26 '16 at 13:06
  • My friend (who gave me this problem) is claiming that it can be done in O(n) too!! – humble Sep 26 '16 at 14:25
  • This is actually O(n^3) because of the repetitive calls to sum(L[i:k]) but it can be lowered down to O(n^2) by using DP, building a table of sums to calculate each sum in O(1). You build an array S with S[i] = S[i-1] + L[i] and sum(L[a:b]) is S[b] - S[a]. But to lower it to O(n) I have to think a bit more... – vz0 Sep 26 '16 at 14:27
  • @rjmessibarca Yes, now that you mention it. It seems to be possible. You build the terms (1+2+3+4+5)*5 = 1*2 + 2*5 + 3*5 + 4*5 + 5*5. You break all the tems and sum each number only once, counting how many times it is present. for 1 is 1*1*16 + 1*2*8 + 1*3*4 + 1*4*2 + 1*5*1 + 1*6*1, for 2 is 2*1*8 + 2*2*4 + 2*3*2 + 2*4*1 + 2*5*1. – vz0 Sep 26 '16 at 14:34
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/124223/discussion-between-rjmessibarca-and-vz0). – humble Sep 26 '16 at 14:34