求3个元素把一串数字均分为4个子串,其和相等 原

题目:

给定一串数字 
判断是否存在这三个元素,它们将数字串分为四个子串,其中每个子串的数字之和均相同(该3个元素不纳入计算) 
要求时间复杂度和空间复杂度均不能超过O(n)

# -*- coding: utf-8 -*-

import random


def split_to_four(n):
    nums = []
    for i in range(n):
        nums.append(random.randint(0, 99))
    # nums = [2, 1, 1, 1, 85, 1, 1, 1, 2]
    # nums = [5,1,3,1,1,3,3,2,2,1,1,1,1,1]
    print nums

    # i 三元素中左侧元素索引
    # j 三元素中右侧元素索引
    i, j = 1, len(nums) - 1

    total = sum(nums)

    k = None  # 三元素中中间元素索引

    # 当i<j,并且中间k还没找到时,继续循环
    while i < j and k is None:
        i, j, k = find_3th_points(i, j, nums, total)

    if k is None:
        return []

    return i, k, j


def find_3th_points(i, j, nums, total):
    """
    根据左右两个点找中间的第三个点
    :param i:
    :param j:
    :param nums:
    :param total:
    :return:
    """
    i, j = find_two_points_on_side(i, j, nums)
    # 假如i,j都交叉了都没找到左右和相等的情况,那么肯定不存在这3个元素
    if i >= j:
        return i, j, None

    # 假如找到左右的位置,那么就把i,j位置中间的元素进行计算,
    # 如果满足总值-左值-右值-中间的值%4==0,以及中间分隔的这段和边上的一样,
    # 那么就找到这个k了,结束程序返回
    # 如果循环完了还没有这个k,则左右都往中间走,继续找两侧相等的i,j点,继续计算
    for k in range(i + 1, j):
        if (total - nums[i] - nums[j] - nums[k]) % 4 == 0 and sum(nums[:i]) == sum(nums[i + 1:k]):
            return i, j, k

    return i + 1, j - 1, None


def find_two_points_on_side(i, j, nums):
    """
    找出两侧分隔元素的位置
    从左侧和右侧分别求和判断是否相等,相等则认为找到i,j,否则根据左右和的大小判断是i往前走1,还是j往左侧走1
    :param i:
    :param j:
    :param nums:
    :return:
    """
    while i < j:
        if sum(nums[:i]) > sum(nums[j:]):
            j -= 1
        elif sum(nums[:i]) < sum(nums[j:]):
            i += 1
        else:
            return i, j - 1
    return i, j


print split_to_four(10)

《求3个元素把一串数字均分为4个子串,其和相等 原》

注意是利用左右两侧数据和相等的特性,再根据4个和相等的特性,找到左右2个,那么总和减去左右2个线,再从中间找个线,能分隔出4个相等的和即为找到了

 

点赞