查找包含不同值

时间:2017-05-08 16:27:04

标签: arrays fortran slice partitioning

我有一个很长的一维正整数数组。从一端开始,我需要找到数组中最长的切片/块,其值与该切片的所有成分相距至少一个数。

即,我想对数组进行分区(从左侧开始),这样每个分区都包含与该分区中所有其他元素相距多于一个单位的元素。

例如:

  1. [1,1,9,5,3,8,7,4,1,2] - > [1],[1,9,5,3],[8],[7,4,1],[2]
  2. [1,5,9,1,3,6,4,2,7,0] - > [1,5,9],[1,3,6,4],[2,7,0]
  3. Bellow,我在Fortran中编写了一些代码,让我找到第一个这样的先前值重现的点。

    • mask是一个LOGICAL数组
    • 数组是有问题的数组
    • n是数组的长度

    我可以轻松扩展它以找到完整的分区。

    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
    

    所以我的问题是,有更好的方法(算法)这样做吗?当我说得更好时,我的意思是速度。我不介意记忆费用。

2 个答案:

答案 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)

我最初的反应是天真的做法:

  • 保存您当前正在展开的分区的索引范围(partitionNumberiStartiEnd
  • 使用索引iEnd+1的下一个点并从iStart循环到iEnd,测试候选点不在当前成员的1之内
  • 如果候选人未通过包含测试,请通过重置iStart并递增partitionNumber
  • 在其自己的分区中启动它
  • 增量iEnd

如果你期望分区大部分都很短,那么这应该很快。如果您期望长整数增加或减少的整数,您可以保存分区中的minmax值包括快速测试,以查看您的候选人是否超出范围。

我没有对此进行测试,我的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,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]
  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]
  3. 我不完全确定我了解如何将您的版本扩展到所有分区,但这可能会节省定义mask大小为MAX(array)的内容吗?