2017-05-08 1 views
0

J'ai un très long tableau unidimensionnel d'entiers positifs. À partir d'une extrémité, j'ai besoin de trouver les plus longues tranches/morceaux du tableau qui ont des valeurs qui sont à au moins un nombre de tous les constituants de cette tranche.Recherche les plus longues tranches d'un tableau contenant des valeurs séparées

C'est-à-dire que je souhaite effectuer un partitionnement du tableau (en partant de la gauche) de sorte que chaque partition contienne des éléments éloignés de tous les autres éléments de cette partition.

Par exemple:

  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]

Ci-dessous, j'ai écrit un petit code en Fortran qui me permettra de trouver le premier point de récurrence d'une valeur précédente.

  • masque est un tableau LOGIQUE
  • tableau
  • est le tableau en question
  • n est la longueur du tableau

Je peux facilement étendre ce pour trouver la partition complète. Donc, ma question est, y a-t-il une meilleure façon (alorithme) de faire cela? Quand je dis mieux, je veux dire la vitesse. Cela ne me dérange pas un coût de mémoire.

+0

@ d_1999 Oh, ce que je veux, c'est un partitionnement tel que chaque tranche n'ait que des nombres éloignés de plus de 1 de tout autre constituant de cette tranche. – physkets

+0

Si vous n'avez pas besoin d'une solution de diffusion en continu, un deuxième tableau des deltas peut être calculé, puis rompez le tableau (de sortie) aux points où vous avez les zéros dans le tableau delta. Obtenir du code vectorisé pour les deltas devrait être facile avec -O3 ou un peu comme un pragma! DIR? SIMD ou!? OMP SIMD (OpenMP) sont faciles. Ensuite, le masque peut toujours être utilisé pour montrer où se trouve le zéro. Cela dépend de la taille d'un très long tableau (?), Mais vous dites que la mémoire n'est pas un problème ... Vous devriez pouvoir limiter la bande passante sur la partie delta vectorisée. Le masque peut également être un nombre entier pour suivre la sous-section du tableau. – Holmz

+0

Juste quelques réflexions: Dans votre premier exemple, est-ce que vous avez autorisé '9' et' 8' à apparaître dans la même tranche? Ne devrait-il pas être [1], [1,9,3], [8], [7,4,1], [2] '? Aussi, cela suit votre règle de * à partir de la gauche *. Dans un cas '[1,1,9,3,8,10,5,1]' voudriez-vous '[1], [1,9,3], [8,10,5,1]' (gauche) ou voulez-vous ramasser la tranche maximale plus longue '[1], [1,9], [3,8,10,5,1]'. – Steve

Répondre

0

Conceptuellement il pourrait ressembler à quelque chose comme ça ...

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) 

Ensuite, il suffit d'imprimer les données entre les valeurs des scissions, qui pourrait être hors d'un compte, et vous devrez peut-être faire quelque chose pour la Nième point, donc cela dépend un peu de votre implémentation et si votre delta est "trop ​​le point suivant" ou "du dernier point".

Dans ce cas, j'ai utilisé imask comme un entier plutôt que logique afin que je puisse utiliser SUM.

+0

J'ai réfléchi à cela, mais je vais devoir trouver des deltas à tous les 'changements'. Le vôtre est à un décalage de 1 unité. Cela ne me donnera que des collisions avec le plus proche voisin. Cela donnera un 'premier' partitionnement. Je ne sais pas si tout cela va le rendre meilleur ou pire. Je suppose que je vais devoir mettre en œuvre les deux et vérifier. – physkets

+0

Vous pouvez toujours avoir un tableau LOGICAL et utiliser COUNT pour effectuer le même travail que SUM. – physkets

+0

Merci @physkets sur le site Intel sous la somme il a mentionné "Internet, réel ou complexe" et je n'ai pas regardé le niveau de bits. Je pourrais probablement utiliser Union/map avec une logique si j'y avais pensé, mais pour le projet sur lequel je travaille, j'avais besoin d'entier de toute façon. – Holmz

0

Ma première réaction est l'approche naïve:

  • sauver des bornes d'index sur la partition que vous êtes actuellement en expansion (partitionNumberiStart-iEnd)
  • Prenez le point suivant avec un indice iEnd+1 et boucle de iStartiEnd testant que le point candidat n'est pas dans 1 des membres actuels
  • Si le candidat échoue au test d'inclusion, démarrez-le dans sa propre partition en réinitialisant iStart et i ncrementing partitionNumber
  • Incrément iEnd.

Si vous attendez que les partitions soient généralement assez courtes, cela devrait être assez rapide.Si vous attendez de longues chaînes d'entiers croissants ou décroissants, vous pouvez enregistrer les min et max de valeurs dans la partition, y compris un test rapide pour voir si votre candidat est en dehors de la plage.

Je n'ai pas testé cela et mon fortran pourrait être un peu rouillé, mais je pense qu'il représente l'algorithme ci-dessus.

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 

Fonctionnant sur vos deux exemples, je l'espère pour revenir arrayMember avec des entrées

  1. [1,1,9,5,3,8,7,4,1,2] -> [1,2,2,2,2,3,4,4,4,5] (REPRÉSENTE [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] (représente [1,5,9],[1,3,6],[4,2,7,0])

Je suis pas tout à fait sûr je comprends comment vous étendez votre version à toutes les partitions, mais cette mi ght sauvegarder sur la définition mask de taille MAX(array)?

+0

Je suppose que cela prendra plus de temps que l'exemple de code que j'ai posté. Dans mon cas, je n'ai pas besoin de calculer les différences à chaque fois. Sinon, il semble identique. N'est-ce pas? – physkets

+0

@physkets Je pense que l'approche est différente: votre code fonctionne pour vérifier une tranche, et pour chaque tranche vous définissez un masque de booléens, longueur 'MAX (tableau)' pour bloquer les entiers, que vous devez déplacer dans , attribuez '.TRUE.' aux valeurs, puis réinitialisez lorsque vous commencez à vérifier la partition suivante.Je ne peux pas commenter sur quelle approche sera la plus rapide, mais je pense que les approches sont suffisamment différentes pour mériter de tester les deux (si mon code compile réellement avec des changements minimes!) – Steve

+0

@physkets Vous avez probablement raison. Comme je l'ai dit, c'était ma première pensée naïve, et j'étais un peu troublé par votre code avec le 'masque (array (i))' que je reçois maintenant – Steve