我刚刚编写了这个实现,以找出使用动态编程的longest increasing subsequence的长度。所以对于[10,22,9,33,21,50,41,60,80]的输入,LIS是6,其中一个是[10,22,33,50,60,80]。
当我运行以下代码时,我得到正确的答案为6,复杂度为O(n)。这是对的吗?
def lis(a):
dp_lis = []
curr_index = 0
prev_index = 0
for i in range(len(a)):
prev_index = curr_index
curr_index = i
print 'if: %d < %d and %d < %d' % (prev_index, curr_index, a[prev_index], a[curr_index])
if prev_index < curr_index and a[prev_index] < a[curr_index]:
print '\tadd ELEMENT: ', a[curr_index]
new_lis = 1 + max(dp_lis)
dp_lis.append(new_lis)
else:
print '\telse ELEMENT: ', a[curr_index]
dp_lis.append(1)
print "DP LIST: ", dp_lis
return max(dp_lis)
if __name__ == '__main__':
a = [10, 22, 9, 33, 21, 50, 41, 60, 80]
print lis(a)
答案 0 :(得分:3)
使用这种正确,经证实但效率低下的算法实现来检查结果 - 它是标准的递归解决方案,它不使用动态编程:
def lis(nums):
def max_length(i):
if i == -1:
return 0
maxLen, curLen = 0, 0
for j in xrange(i-1, -1, -1):
if nums[j] < nums[i]:
curLen = max_length(j)
if curLen > maxLen:
maxLen = curLen
return 1 + maxLen
if not nums:
return 0
return max(max_length(x) for x in xrange(len(nums)))
检查your_lis(nums) == my_lis(nums)
是否有尽可能多的不同大小的输入列表,它们应该相等。在某些时候,对于长列表,我的实现将远远慢于你的。
作为进一步的比较点,这是我自己的优化动态编程解决方案。它在O(n log k)
时间和O(n)
空间运行,返回它沿途发现的实际最长的增长子序列:
def an_lis(nums):
table, lis = lis_table(nums), []
for i in xrange(len(table)):
lis.append(nums[table[i]])
return lis
def lis_table(nums):
if not nums:
return []
table, preds = [0], [0] * len(nums)
for i in xrange(1, len(nums)):
if nums[table[-1]] < nums[i]:
preds[i] = table[-1]
table.append(i)
continue
minIdx, maxIdx = 0, len(table)-1
while minIdx < maxIdx:
mid = (minIdx + maxIdx) / 2
if nums[table[mid]] < nums[i]:
minIdx = mid + 1
else:
maxIdx = mid
if nums[i] < nums[table[minIdx]]:
if minIdx > 0:
preds[i] = table[minIdx-1]
table[minIdx] = i
current, i = table[-1], len(table)
while i:
i -= 1
table[i], current = current, preds[current]
return table
答案 1 :(得分:1)
我经常使用动态编程算法。
我发现检查正确性的最佳方法是编写算法的暴力版本,并将输出与动态编程实现进行比较。
如果两个版本的输出一致,那么您对正确性有合理的信心。