Home > database >  Hairpin structure easy algorithm
Hairpin structure easy algorithm

Time:01-18

I have a structure with letters A, Z, F, G.

A have a pair with Z, and F with G.

I have for example AAAFFZZGGFFGGAAAAZZZZ. And I need to "curve" structure and that fold will make a pairs

A A A F F Z Z G G F F -
  * *     * *     * *  |
  Z Z Z Z A A A A G G -

6 pairs in upper example.

But we can create structure like this:

      A A A F F Z Z G G -
      *             * *  |
Z Z Z Z A A A A G G F F - 

And head is a fragment of structure where pairs cannot exists. For example head 2:

rozmiar. Na przykład head = 2:

                    F F
A A A F F Z Z G G  /   \
  * *     * *           |
  Z Z Z Z A A A A  \   /
                    G G

I don't know how to find maximal number of pairs that can be created in this structure

CodePudding user response:

You could start with testing the folding point in the center, and then fan out (in zig-zag manner) putting the folding point further from the center.

Then for a given folding point, count the allowed pairs. You can use slicing to create the two strips, one in reversed order, and then zip those to get the pairs.

The outer iteration (determining the folding point) can stop when the size of the shortest strip is shorter than the size of the best answer found so far.

Here is a solution, which also returns the actual fold, so it can be printed for verification:

def best_fold(chain):
    allowed = set(("AZ","ZA","FG","GF"))
    revchain = chain[::-1]
    maxnumpairs = 0
    fold = chain  # This represents "no solution"
    n = len(chain)
    head = n // 2
    for diff in range(n):
        head  = diff if diff % 2 else -diff
        if head - 2 < maxnumpairs or n - head - 2 < maxnumpairs:
            break
        numpairs = sum(a b in allowed
            for a, b in zip(revchain[-head 2:], chain[head 2:])
        )
        if numpairs > maxnumpairs:
            maxnumpairs = numpairs
            fold = chain[:head].rjust(n)   "\n"   revchain[:-head].rjust(n)        

    return maxnumpairs, fold

Here is how to run it on the example string:

numpairs, fold = best_fold("AAAFFZZGGFFGGAAAAZZZZ")
print(numpairs)  # 5
print(fold)      #   AAAFFZZGGF
                 #  ZZZZAAAAGGF

CodePudding user response:

To make the matching go faster you can prepare a second string (R) with the letters flipped to their corresponding values. This will allow direct comparisons of paired positions instead of going through an indirection n^2 times:

S = "AAAFFZZGGFFGGAAAAZZZZ"

match = str.maketrans("AZFG","ZAGF")
R = S.translate(match)                # flipped matching letters

mid = len(S)//2
maxCount,maxPos = 0,0
for d in range(mid 1):        # moving away from middle
    for p in {mid d,mid-d}:   # right them left  
        pairs = sum(a==b for a,b in zip(S[p-1::-1],R[p:])) # match fold
        if pairs>maxCount:
            maxCount,maxPos = pairs,p  # track best so far and fold position
    if p <= maxCount: break            # stop when impossible to improve 
        
print(maxCount)                         # 6 matches
print(maxPos)                           # folding at 11
print(S[:maxPos].rjust(len(S)))         #          AAAFFZZGGFF
print(S[maxPos:][::-1].rjust(len(S)))   #           ZZZZAAAAGG
                                        #           **  **  **
  •  Tags:  
  • Related