调试最长递增子序列-Ruby

调试最长递增子序列-Ruby,ruby,algorithm,subsequence,Ruby,Algorithm,Subsequence,我正在通过Leetcode解决以下问题: 给定一个未排序的整数数组,求最长递增子序列的长度 a = longest_increasing_sequence(arr) #=> [2, 5, 11, 13, 14, 15, 17] a.each_with_object({}) { |n,h| h[n] = arr[n] } #=> {2=>13, 5=>16, 11=>18, 13=>24, 14=>27, 15=>63, 17=>83}

我正在通过Leetcode解决以下问题:

给定一个未排序的整数数组,求最长递增子序列的长度

a = longest_increasing_sequence(arr)
  #=> [2, 5, 11, 13, 14, 15, 17]
a.each_with_object({}) { |n,h| h[n] = arr[n] }
  #=> {2=>13, 5=>16, 11=>18, 13=>24, 14=>27, 15=>63, 17=>83}
例如,给定[10,9,2,5,3,7,101,18],最长的 递增子序列为[2,3,7,101],因此长度为4。 请注意,可能有多个LIS组合,仅适用于 您必须返回长度

您的算法应该以O(n2)复杂度运行

跟进:你能把时间复杂度提高到O(n logn)吗

尝试实现第一个蛮力解决方案,本质上是一种递归方法,生成每个递增子序列,然后获取长度最大的子序列。在我实现这个之后,我将使用动态规划来优化。我发现自己对暴力的实现有点困惑——以下是我的代码:

def length_of_lis(nums)
    1 + max_len(nums, 1, nums.first)
end

def max_len(nums, index, prev_number)
    current_num = nums[index]
    max = 0 
    return 0 if index >= nums.length     
    if current_num > prev_number
        max = [1 + max_len(nums, index + 1, current_num), max].max
    else
        max = [max_len(nums, index + 1, prev_number), max].max
    end 
    max = [1 + max_len(nums, index + 1, current_num), max].max

    max
end
现在我知道这显然是不正确的,但我想说的是,在每个数字上,都会发生一些事情。1)它被传递一个来自前一个数字的函数,如果当前数字大于前一个数字,则继续该函数用于LIS。2) 以当前编号创建新的LIS子序列

正如您所知,这会创建两行相同的代码,我不确定如何构造代码,以使两个不同的事情发生,并且max变量包含最终值。有没有关于如何相应调整此代码的想法

我曾经得到过一个最优解

代码

def construct_sequence(longest, max_i)
  a = []
  loop do
    a << max_i
    max_i = longest[max_i][:next]
    return a if max_i.nil?
  end
end      

def longest_increasing_sequence(arr)
  longest = Array.new(arr.size)
  longest[arr.size-1] = { length: 1, next: nil }
  (arr.size-2).downto(0) do |i|
    best_seq = { length: 1, next: nil }
    (i+1).upto(arr.size-1) do |j| 
      next if arr[j] <= arr[i]
      h = longest[j]      
      best_seq = { length: 1 + h[:length], next: j } if h[:length] >= best_seq[:length]
    end
    longest[i] = best_seq
  end
  max_i = (0..arr.size-1).max_by { |i| longest[i][:length] }
  construct_sequence(longest, max_i)
end
arr = [10, 9, 2, 5, 3, 7, 101, 18]
a = longest_increasing_sequence(arr)
  #=> [2, 3, 5, 6] 
a.each_with_object({}) { |n,h| h[n] = arr[n] }
  #=> {2=>2, 3=>5, 5=>7, 6=>101}
对于第二个示例,我构建了以下20个元素的伪随机数组

arr = (1..99).to_a.sample(20)
  #=> [80, 75, 13, 12, 85, 16, 41, 89, 93, 56, 74, 18, 37, 24, 27, 63, 47, 83, 25, 44]
最长递增序列
返回构成最长递增序列的
arr
索引数组

a = longest_increasing_sequence(arr)
  #=> [2, 5, 11, 13, 14, 15, 17]
a.each_with_object({}) { |n,h| h[n] = arr[n] }
  #=> {2=>13, 5=>16, 11=>18, 13=>24, 14=>27, 15=>63, 17=>83}
解释

数组的每个元素都有一个阶段。状态变量是最长递增序列(“LIS”)开始的数组的索引。我们从数组的最后一个元素开始,在上面的例子中是
arr[19]
。如果递增序列(“IS”)从那里开始,它也从那里结束。该序列的长度为
1

然后我们回到第18阶段。有两种可能性:从该阶段开始的LS的长度为
1
,或在第19阶段继续(如果序列增加),在这种情况下,LS的长度为
2

更一般地说,如果LIS从索引
i
开始,它可能在那里结束或继续,其中
j
是LIS中的下一个索引,其中
i+1i用于获得最佳解决方案

代码

def construct_sequence(longest, max_i)
  a = []
  loop do
    a << max_i
    max_i = longest[max_i][:next]
    return a if max_i.nil?
  end
end      

def longest_increasing_sequence(arr)
  longest = Array.new(arr.size)
  longest[arr.size-1] = { length: 1, next: nil }
  (arr.size-2).downto(0) do |i|
    best_seq = { length: 1, next: nil }
    (i+1).upto(arr.size-1) do |j| 
      next if arr[j] <= arr[i]
      h = longest[j]      
      best_seq = { length: 1 + h[:length], next: j } if h[:length] >= best_seq[:length]
    end
    longest[i] = best_seq
  end
  max_i = (0..arr.size-1).max_by { |i| longest[i][:length] }
  construct_sequence(longest, max_i)
end
arr = [10, 9, 2, 5, 3, 7, 101, 18]
a = longest_increasing_sequence(arr)
  #=> [2, 3, 5, 6] 
a.each_with_object({}) { |n,h| h[n] = arr[n] }
  #=> {2=>2, 3=>5, 5=>7, 6=>101}
对于第二个示例,我构建了以下20个元素的伪随机数组

arr = (1..99).to_a.sample(20)
  #=> [80, 75, 13, 12, 85, 16, 41, 89, 93, 56, 74, 18, 37, 24, 27, 63, 47, 83, 25, 44]
最长递增序列
返回构成最长递增序列的
arr
索引数组

a = longest_increasing_sequence(arr)
  #=> [2, 5, 11, 13, 14, 15, 17]
a.each_with_object({}) { |n,h| h[n] = arr[n] }
  #=> {2=>13, 5=>16, 11=>18, 13=>24, 14=>27, 15=>63, 17=>83}
解释

数组的每个元素都有一个阶段。状态变量是最长递增序列(“LIS”)开始的数组的索引。我们从数组的最后一个元素开始,在上面的例子中是
arr[19]
。如果递增序列(“IS”)从那里开始,它也从那里结束。该序列的长度为
1

然后我们回到第18阶段。有两种可能性:从该阶段开始的LS的长度为
1
,或在第19阶段继续(如果序列增加),在这种情况下,LS的长度为
2


更一般地说,如果LIS从索引
i
开始,它可能在那里结束或继续,其中
j
是LIS中的下一个索引,其中
i+1我没有回答您的问题,因为我无法理解您正在做的事情。(前两行代码特别奇怪。可能是一个工件?)然而,我确实提供了一个动态编程解决方案(我看到了您的下一步)。我认为DP绝对是一种方式。它是O(n^2),但我认为没有更快的解决方案。前两个实际上应该被注释掉——它们是为了让网站用户知道输入和输出应该是什么。我当然会分析你提供的解决方案,但这有助于我理解我在思考过程中的错误,而不是简单地看一个解决方案/阅读它的解释。我删除了前两行--我可以为您编辑其他内容或解释一些内容吗?我没有回答您的问题,因为我无法理解您在做什么。(前两行代码特别奇怪。可能是一个工件?)然而,我确实提供了一个动态编程解决方案(我看到了您的下一步)。我认为DP绝对是一种方式。它是O(n^2),但我认为没有更快的解决方案。前两个实际上应该被注释掉——它们是为了让网站用户知道输入和输出应该是什么。我当然会分析你提供的解决方案,但这有助于我理解我在思考过程中的错误,而不是简单地看一个解决方案/阅读它的解释。我删除了前两行--我可以为您编辑其他内容或解释其他内容吗?