简体   繁体   中英

Explore all sub-sequence

I'm trying already for some days to solve this problem without any success.

About this problem:

Given a sequence '2 2 4 4'.

We take consecutively 2 numbers from the sequence, For example: 2 2 ,2 4, 4 4.

If the sum of the 2 numbers is an number divisible by 2 we replace the 2 numbers and put the result of the 2 numbers for example: (2+2 = 4, 4/2 = 2) so the new sequence is (2 4 4), but here I should find all possible sequences. If no possible to find an even number that is dividable by 2, so we return the sequence.

A picture of how should it be

图片应该如何

The red rectangles are the sequence that I cannot get :(

my code:

def recFunc(n):
    for i in range(len(n)):
        if i+1 <= len(n)-1: #control out of range
            if ((n[i] + n[i+1]) % 2 == 0):
                newnum = int((n[i] + n[i+1])/2)
                n[i:i+2] = [newnum]
                return recFunc(n)
            else:
                if i+1 == len(n)-1:
                    return [n]
                else:
                    continue
def main(s):
    s = s.split()
    integers = [int(x) for x in s]
    final = recFunc(integers)
    print(final)

main('2 2 4 4')

What I did here is ,converted the sequence to integers , sent them to a new function. That I should receive all sequences recursively.

I iterated on the sequence and taking the first number by n[i] and the second n[i+1] (and controlling if I can have the second number to not get out of range).

The final result should be ordered in increasing mode of the size sequence, if the length of the 2 sequence is that same so we order by the first number of the sequence.

At the end I should receive ['3', '2 3', '3 4', '2 3 4']

Below is my recursive solution, based on your diagram, which can handle '30 20 10 30 6 6' without stack issues. Data conversion, sorting and redundancy reduction are handled by the main() routine. The sub_sequence() function takes an array and returns an array of arrays that match the logic of your diagram:

def sub_sequence(array):
    solutions = []

    length = len(array)
    changed = False

    if length > 1:
        for index in range(len(array) - 1):
            prefix, pair, postfix = array[:index], array[index:index + 2], array[index + 2:]

            total = sum(pair)

            if total % 2 == 0:
                solutions.extend(sub_sequence([*prefix, total // 2, *postfix]))
                changed = True

    if length < 2 or not changed:
        solutions.append(array)

    return solutions

def main(string):
    unsorted_redundant_sub_sequences = sub_sequence([int(number) for number in string.split()])
    unsorted_non_redundant_strings = set(" ".join(map(str, sequence)) for sequence in unsorted_redundant_sub_sequences)
    sorted_non_redundant_strings = sorted(unsorted_non_redundant_strings, key=lambda x: (len(x), x))
    print(sorted_non_redundant_strings)

main('30 20 10 30 6 6')

OUTPUT

> python3 test.py
['18', '19', '19 6', '25 6', '25 10', '25 14', '30 13', '30 15', '30 17', '30 13 6', '30 17 6', '30 15 12', '30 15 18']
> 

I created a few functions to accomplish the goal:

  1. least_check that give a True / False as to whether or not the sequence is a "least" (eg '2 4' would return False , while '3 4' would return True )
  2. find_leasts which is the recursive function that breaks a sequence down to the the next level in the tree shown in the question (eg '2 2 4 4' would break down to '2 4 4' , '2 3 4' , and '2 2 4' ) until it reaches all "leasts"
  3. main which creates a list of all the "leasts" yield ed from the find_leasts function, and removes any duplicates (eg example sequence has '3' twice) and returns the list of unique "leasts"

Answer:

def least_check(n):
    check_list = [int(x) for x in n.split(' ')]
    for a, b in zip(check_list[:-1], check_list[1:]):
        if (a + b) % 2 == 0:
            return False
    return True

def find_leasts(n):
    if len(n.split(' ')) == 1:
        yield n
    for i in range(len(n.split(' '))-1):
        s = [int(x) for x in n.split(' ')]
        if (s[i] + s[i+1]) % 2 == 0:
            s[i] = int((s[i] + s[i+1]) / 2)
            s.pop(i+1)
        sub_n = ' '.join(str(j) for j in s)
        if least_check(sub_n):
            yield sub_n
        else:
            yield from find_leasts(sub_n)

def main(s):
    all_leasts = [x for x in find_leasts(s)]
    unique_leasts = list(set(all_leasts))
    return unique_leasts

seq = '2 2 4 4'
print(sorted(main(seq), key=len))

Result:

['3', '2 3', '3 4', '2 3 4']

Update:

The above solution has many split() s and ' '.join() s in order to avoid the recursive function modifying a list reference (a list name is a pointer to its memory address - if needed, see this site for further explanation) from a depth other than the current scope.

When looking at the error received on a '30 20 10 30 6 6' sequence and considering that playing with the max recursion via sys.setrecursionlimit is not recommended , I re-evaluated whether or not recursion was even necessary - and determined it is not.

Here are the functions used in the iterative solution:

  1. least_check - same as original answer
  2. break_down - takes a list and breaks it down to all lists down one level in the tree (eg '2 2 4 4' would break down to '2 4 4' , '2 3 4' , and '2 2 4' )
  3. least_lister - iterates through the queue of lists that are potential leasts, until all lists in least_lists are leasts
  4. main - does all split() and ' '.join() operations and removes duplicates before returning results

Iterative Solution:

def least_check(check_list):
    for a, b in zip(check_list[:-1], check_list[1:]):
        if (a + b) % 2 == 0:
            return False
    return True

def break_down(s, ret):
    for i in range(len(s)-1):
        if (s[i] + s[i+1]) % 2 == 0:
            bd_list = s.copy()
            bd_list[i] = int((bd_list[i] + bd_list[i+1]) / 2)
            bd_list.pop(i+1)
            ret.append(bd_list)

def least_lister(n):
    least_lists = []
    if least_check(n):
        least_lists.append(n)
    else:
        i = 0
        break_down(n, least_lists)
        while i < len(least_lists):
            if least_check(least_lists[i]):
                i+=1
            else:
                break_down(least_lists[i], least_lists)
                least_lists.pop(i)
    return least_lists

def main(s):
    s_list = [int(x) for x in s.split(' ')]
    all_leasts = least_lister(s_list)
    unique_leasts = list(set([' '.join(str(j) for j in i) for i in all_leasts]))
    return unique_leasts

seq = '30 20 10 30 6 6'
print(sorted(main(seq), key=len))

Iterative Result:

['18', '19', '19 6', '25 6', '25 10', '25 14', '30 13', '30 15', '30 17', '30 13 6', '30 17 6', '30 15 12', '30 15 18']

List Reference Example

def add_to_list(n):
    n.append(len(n))
    print(n)

a = [0, 1]

add_to_list(a)
print(a)

List Reference Example Output:

[0, 1, 2]
[0, 1, 2]

Let's see this problem step by step.

First : Sum the first number of the array with the second one,

divide by two the result,

create a new array with the new values,

if it's even

then call recursive on the new arrey

Else put the new arrey in a static data structure

Second : At the first point we need to see all the index,

Put everything in a cycle starting with index I = 0 to length-2

Third : work on the static array, sort it as you want and print the result.

I'm not good with python but I hope this pseudo code will help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM