我有一个很长的一维正整数数组。从一端开始,我需要找到数组中最长的切片/块,其值与该切片的所有成分相距至少一个数。
即,我想对数组进行分区(从左侧开始),这样每个分区都包含与该分区中所有其他元素相距多于一个单位的元素。
例如:
Bellow,我在Fortran中编写了一些代码,让我找到第一个这样的先前值重现的点。
我可以轻松扩展它以找到完整的分区。
mask = .FALSE.
DO i = 1,n
k = array(i)
IF ( mask(k) ) THEN
PRINT*, i
EXIT
ELSE
mask(k-1 : k+1) = .TRUE.
END IF
END DO
所以我的问题是,有更好的方法(算法)这样做吗?当我说得更好时,我的意思是速度。我不介意记忆费用。
答案 0 :(得分:0)
从概念上讲,它可能看起来像这样......
DO i = 1,n-1
Delta(I) = array(I+1) - array(I)
ENDDO
iMask = 0
WHERE(ABS(Delta) < 2) iMask =1
ALLOCATE(splits(SUM(iMask)))
K=0
DO I = 1, n-1
IF(iMask(I) == 0) CYCLE
K = K +1
Splits(K) = I
ENDDO
!... DEALLOCATE(Splits)
然后只打印分割值之间的数据,这可能会被计数关闭,您可能还需要为第N个点做一些事情,所以它取决于您的实现以及您的delta是否“太”下一个点“或”从最后一点“。
在这种情况下,我使用imask作为整数而不是逻辑,所以我可以使用SUM。
答案 1 :(得分:0)
我最初的反应是天真的做法:
partitionNumber
从iStart
到iEnd
)iEnd+1
的下一个点并从iStart
循环到iEnd
,测试候选点不在当前成员的1之内iStart
并递增partitionNumber
iEnd
。如果你期望分区大部分都很短,那么这应该很快。如果您期望长整数增加或减少的整数,您可以保存分区中的min
和max
值包括快速测试,以查看您的候选人是否超出范围。
我没有对此进行测试,我的fortran可能有点生疏,但我认为它代表了上述算法。
partitionNumber = 1
iStart = 1
iEnd = 1
iCandidate = iEnd + 1
arrayMember(iStart) = partitionNumber
DO WHILE (iCandidate <= N)
DO j = iStart,iEnd
IF ( ABS(array(iCandidate)-array(j)) < 2 )
partitionNumber = partitionNumber + 1
iStart = iCandidate
EXIT
END IF
END DO
arrayMember(iCandidate) = partitionNumber
iEnd = iEnd + 1
iCandidate = iEnd + 1
END DO
根据您的两个示例操作,我希望它返回arrayMember
条目
[1,1,9,5,3,8,7,4,1,2] -> [1,2,2,2,2,3,4,4,4,5]
(代表[1],[1,9,5,3],[8],[7,4,1],[2]
)[1,5,9,1,3,6,4,2,7,0] -> [1,1,1,2,2,2,3,3,3,3]
(代表[1,5,9],[1,3,6],[4,2,7,0]
)我不完全确定我了解如何将您的版本扩展到所有分区,但这可能会节省定义mask
大小为MAX(array)
的内容吗?