找到一组数字中的最小总和

时间:2016-04-04 14:23:15

标签: excel excel-vba excel-formula vba

我试图找到一张excel表中行数的连续数字的最小总和。 10.000行。

1 200
2 -100
3 -300
4 100
5 100
6 100

这应该给出-400和2行(当然这可以在另一个公式中)。

1 0
2 100
3 -100
4 -100
5 -100
6 100
7 -100
8 100

这应该给出-300和3行等。

谢谢!

2 个答案:

答案 0 :(得分:2)

使用数组这个过程在10,000行上花费3-4秒:

Sub minarr()

Dim i&, j&
Dim rngArr() As Variant
Dim sum As Double
Dim frstrw As Long
Dim lstrw As Long
Dim lastrow As Long
Dim ws As Worksheet
Dim Minout As Double

Set ws = Sheets("Sheet28") 'Change to your sheet

'Change column A to the column of your numbers in the next two lines.
lastrow = ws.Range("A" & ws.Rows.Count).End(xlUp).row
rngArr = ws.Range("A1:A" & lastrow).Value

For i = 1 To lastrow
    sum = rngArr(i, 1)
    For j = i + 1 To lastrow
        sum = sum + rngArr(j, 1)
        If sum < Minout Then
            Minout = sum
            frstrw = i
            lstrw = j
        End If
    Next j
Next i

Debug.Print Minout
Debug.Print frstrw
Debug.Print lstrw

End Sub

答案 1 :(得分:2)

Here is a debugged O(n) solution. It is virtually instantaneous with 10,000 items. The algorithm is a variation of Kadane's algorithm for solving the maximum subarray problem (which @rajah9 points out as being a close match to this problem):

Function MinSum(Target As Range) As Variant
    'Target is a 1-dimensional range of numbers
    'Returns a variant array containing
    '0) The minimum sum of consecutive numbers in R
    '1) The starting index of the sum
    '2) The ending index of the sum

    Dim i As Long, n As Long
    Dim A As Variant 'A(i,1) = value of best subsequence ending at i, A(i,2) is corresponding start value
    Dim v As Variant 'currently scanned value
    Dim minS As Variant 'the min sum
    Dim minAt As Variant 'where it occurs in A

    With Target
        'initialize
        n = .Cells.Count
        ReDim A(1 To n, 1 To 2)
        v = .Cells(1)
        minS = v
        minAt = 1
        A(1, 1) = v
        A(1, 2) = 1

        'main loop
        For i = 2 To n
            v = .Cells(i)
            'the best sequence ending at i extends previous one if previous one is negative:
            If A(i - 1, 1) < 0 Then
                A(i, 1) = A(i - 1, 1) + v
                A(i, 2) = A(i - 1, 2) 'extend current subsequence
            Else 'start new subsequence
                A(i, 1) = v
                A(i, 2) = i
            End If
            'see if we have a new min:
            If A(i, 1) < minS Then
                minS = A(i, 1)
                minAt = i
            End If
        Next i
    End With

    MinSum = Array(minS, A(minAt, 2), minAt)
End Function

It returns an array which gives both the minimal sum and two indices, start and end of the sum in the array. It can be used as an array formula:

enter image description here

In the above screenshot, I have =RANDBETWEEN(-100,100) in cells A1:A10000 and then in cells C1:E1 I have {=MinSum(A1:A10000)} (Ctrl+Shift+Enter to accept as an array formula). Both the computation of the 10,000 random numbers and the determination of the minsum takes less than half a second.