中级农民
- 积分
- 129
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2016-1-11
- 最后登录
- 1970-1-1
|
本帖最后由 stonepeter 于 2024-2-25 21:40 编辑
LIS 题 如何在实现O(n logn)的同时不能重建LIS
Intuition
Approach
The O(n log n) solution for finding the length of the longest increasing subsequence (LIS) in an array involves a combination of dynamic programming and binary search. The key idea here is to maintain an array that stores the smallest possible tail element for subsequences of different lengths. Here's how it works:
Initialization: Create an array tails to store the last element of the increasing subsequences. Initially, it is empty.
Iterate Through the Array: For each element num in the input array nums, do the following:
If num is larger than all elements in tails, append it to tails. This extends the longest subsequence found so far.
Otherwise, find the position of the smallest element in tails that is greater than or equal to num (using binary search) and replace it with num. This step ensures that the subsequence remains increasing and updates it to have the smallest possible elements, which allows for longer subsequences in the future.
Length of LIS: The length of the longest increasing subsequence is the size of the tails array after processing all elements.
The problem/question: How to rebuild the LIS List?
Below code is an extension of the O(n log n) algorithm for finding the length of the Longest Increasing Subsequence (LIS), with the additional feature of tracking the predecessor of each element that contributes to the final LIS. This tracking allows us to reconstruct the actual LIS, not just calculate its length
updating tails and result_dct:
If idx equals the length of tails, it means num is larger than all elements in tails. So, append num to tails. In result_dct, map num to the last element in tails (or float('inf') if tails is empty), indicating that num extends the longest subsequence found so far.
If idx is less than the length of tails, it means num should replace the current element at tails[idx]. In result_dct, map num to tails[idx-1], indicating that the predecessor of num in the subsequence is tails[idx-1].
Reconstructing the LIS:
After processing all elements, we reconstruct the LIS in reverse order, starting from the last element in tails and tracing back through the predecessors recorded in result_dct.
The reconstructed LIS is stored in result, which is then printed in reverse to show the LIS in the correct order.
Complexity
Time complexity:
O(nlog(n))O(n log (n))O(nlog(n))
Code
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
result_dct = {}
tails = []
for num in nums:
idx = bisect_left(tails, num)
if idx == len(tails):
result_dct[num] = tails[-1] if tails else float('inf')
tails.append(num)
else:
tails[idx] = num
result_dct[num] = tails[idx-1] if (idx-1) >= 0 else float('inf')
result = []
tail = tails[-1]
while tail != float('inf'):
result.append(tail)
tail = result_dct[tail]
print(result[::-1])
return len(tails) |
|