【问题标题】:Finding the number of ways I can split a list into two parts so that each item in the left part is smaller than each item in the right part找到我可以将列表分成两部分的方法数,以便左侧的每个项目都小于右侧的每个项目
【发布时间】:2021-01-06 20:19:36
【问题描述】:

一种算法,用于查找我可以将列表分成两部分的方法数量,以便左侧的每个项目都小于右侧的每个项目。

目前,我有以下功能,但这并不完全有效...此外,我需要能够在 O(n) 中执行此操作,因为嵌套循环不是这个功能...

def get_subsets(l): 
   n = len(l) 
   subsets = [] 
   for i in range(n + 2): 
       for j in range(i + 2, n + 1): 
           if l[i:j][-1] > l[i:j][-2]:
              subsets.append(l[i:j]) 
   return subsets 

例如对于输入 [2,1,2,5,7,6,9] 将有 3 种方式 [2,1,2], [5,7,6,9][2,1,2,5], [7,6,9][2,1,2,5,7,6], [9].

我当前的函数只返回

[[2, 1, 2],
 [2, 1, 2, 5],
 [2, 1, 2, 5, 7],
 [2, 1, 2, 5, 7, 6, 9],
 [1, 2],
 [1, 2, 5],
 [1, 2, 5, 7],
 [1, 2, 5, 7, 6, 9],
 [2, 5],
 [2, 5, 7],
 [2, 5, 7, 6, 9],
 [5, 7],
 [5, 7, 6, 9],
 [7, 6, 9],
 [6, 9]]

为此...我应该做什么样的修改?

【问题讨论】:

    标签: python dynamic dynamic-programming


    【解决方案1】:

    目标:

    ...使得左侧的每个项目都小于右侧的每个项目

    为了实现这个目标,

    1. 左侧的每个项目都应严格小于右侧分区中的“最小”项目。
    2. 右侧的每个项目都应大于左侧分区中的“最大”项目。

    进一步减少这两个步骤,检查以下内容就足够了:

    • 左分区的最大值严格小于右分区的最小值。

    注意:现在看您的示例,似乎我们只是在寻找左前缀和右后缀分区,从而按照我们的目标消耗整个列表。

    蛮力(O(N * N * N) 时间和 O(1) 空间复杂度):

    def get_subsets(l): 
       n = len(l)
       subsets = [] 
       for i in range(1, n):  # O(N) time
         if max(l[:i]) < min(l[i:]): # O(N) time for min and max functions
            subsets.append(l[:i]) # O(N) time to add answers
            subsets.append(l[i:])
       return subsets 
    

    暴力破解分析:

    maxmin 操作一起是 O(N),因为数组中的总数是 N,我们对所有数字进行操作,还有一个 O(N) 的外循环。由于我们还想要子集,因此创建和添加子集需要额外的 O(N) 时间。因此,当元素按排序顺序排列时,总运行时复杂度在最坏情况下变为 O(N * N * N)。

    运行时改进的范围:我们能否在 O(1) 时间内计算出左分区的最大项和右分区的最小项?是的,我们可以通过预先计算所有可能的正确分区的最小值来实现这一点。但这是以 O(N) 额外空间为代价的。我们将在迭代时动态计算左分区的最大项。

    优化的运行时间(O(N * N) 时间和 O(N) 空间复杂度):

    def get_subsets(l): 
       n = len(l)
       subsets = []
       
       # precalculation step begin
       min_suffix = l.copy() # min_suffix[i] is minimum item after index i including i 
       for i in range(n-2,-1,-1):
          min_suffix[i] = min(min_suffix[i+1], l[i])
       # precalculation step end
    
       max_prefix_till_now = l[0] # we will maintain maximum item seen till now and update on the fly
    
       for i in range(1, n): 
         if max_prefix_till_now < min_suffix[i]:
            subsets.append(l[:i])
            subsets.append(l[i:])
         max_prefix_till_now = max(max_prefix_till_now, l[i]) # update maximum on the fly
       return subsets
    

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 2021-01-21
      • 2019-03-08
      • 2019-02-02
      • 2017-09-29
      • 2016-08-18
      • 2016-06-15
      • 1970-01-01
      相关资源
      最近更新 更多