Job Scheduling Algorithm
Functions
It's good that you're thinking about how to capture code in functions, but you haven't particularly chosen the right code to move into functions.
This is somewhat trivial:
print(&quot;profit: &quot; + str(profit), end = &quot;\n&quot;)

and does not deserve its own function; simply write
print(f'profit: {profit}')

at the outer level. The same applies for output_subset, which does not need a loop and can be
    print(' '.join(item for item in subset))

Instead, something that does deserve to be in a separate function is your set of loops starting at for row, which can be translated into a generator; also note that 0 is the default start for range:
ProfitPair = Tuple[
    int,
    List[str],
]


def get_profits( ... variables needed for iteration ...) -&gt; Iterable[ProfitPair]:
    for row in range(len(items)):
        for col in range(len(items) + 1):
            subset = items[row:col]
            for job_index in range(len(subset)):
                if items_starts[job_index] &gt;= machine_starts[job_index]:
                    if items_ends[job_index] &lt;= machine_ends[job_index]:
                        done_tasks[job_index] = done_tasks[job_index] + 1
            profit = 0 
            for job_index in range(len(subset)):
                if tasks_to_complete[job_index] == done_tasks[job_index]:
                    profit += profits_for_job[job_index]
            
            yield (profit, subset)

Type hints
It's good that you've tried this out. subset:[str] should be subset: List[str].
Indexing
for row in range(0, len(items)):
    for col in range(0, len(items) + 1):
        subset = items[row:col]

seems strange to me. Based on your initialization, items is not a two-dimensional (nested) list - unless you count string indexing as the second dimension. row and col are thus somewhat misnamed, and are basically start and end.
In-place addition
done_tasks[job_index] = done_tasks[job_index] + 1

should be
done_tasks[job_index] += 1

Summation with generators
        profit = 0 
        for job_index in range(0, len(subset)):
            if tasks_to_complete[job_index] == done_tasks[job_index]:
                profit = profit + profits_for_job[job_index]
        

can be
profit = sum(
    profits_for_job[job_index]
    for job_index in range(len(subset))
    if tasks_to_complete[job_index] == done_tasks[job_index]
)

This raises another point, though. Consider &quot;rotating&quot; your data structure so that, instead of multiple sequences where the same index in each correspond to a description of the same thing, e.g.
profits_for_job[job_index]
tasks_to_complete[job_index]
done_tasks[job_index]

instead have a sequence of @dataclasses with attributes:
job[job_index].profits
job[job_index].tasks_to_complete
job[job_index].tasks_done

Predicate combination
            if items_starts[job_index] &gt;= machine_starts[job_index]:
                if items_ends[job_index] &lt;= machine_ends[job_index]:
                    done_tasks[job_index] = done_tasks[job_index] + 1

can just be
if (
    items_starts[job_index] &gt;= machine_starts[job_index] and
    items_ends[job_index] &lt;= machine_ends[job_index]
):
    done_tasks[job_index] += 1