题解 | #合唱队#

合唱队

https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4

合唱队问题是要找到一个领唱(leader),他的左侧和右侧分别形成两个单调子序列。

耐心纸牌游戏是求单调子序列的一种高效的求解方法,其复杂度为 O(nlogn)。

输入是一个乱序的牌堆,从中每次抽一张牌,正面朝上摆在桌上,最终要按一定规则摆成一到多堆。最初,抽第一张牌,桌上只有一堆牌;之后的每一张牌,从左到右的各牌堆中,如果值比场上某一堆的牌的最面上的牌小或相等,则抽牌放在符合条件的最左侧牌堆之上,如果不存在这样的堆,则新建一个堆放在现有牌堆的最右侧;直到放完最后一张牌,就可以得到多个有序子串。

用耐心游戏摆出的牌堆的堆数,就是发牌序列所对应的最长递增子列长度。不过,此题需加上限定最后一张牌一定位于该子序列中,此时最后一张发牌所落至堆序数,就是包含它的最长递增子列长度。

以下代码的编码过程中参考了 牛友 sparrow。 的解答

import sys
import bisect

num_students = int(input())
students = list(map(int, input().split(" ")))


def play_patience_game(cards) -> list[int]:
    LIS: list[int] = [None] * len(cards)
    piles = []  # 牌堆
    for icard, card in enumerate(cards):  # 发牌
        if icard == 0 or card > piles[-1]:
            piles.append(card)  # 新增一个牌堆
            LIS[icard] = len(piles)
        else:
            pos = bisect.bisect_left(piles, card)
            piles[pos] = card  # 放到牌堆最上面
            LIS[icard] = pos + 1
    return LIS


left = play_patience_game(students)
right = play_patience_game(students[::-1])[::-1]

L = max([(left[leader] + right[leader] - 1) for leader in range(len(students))])

print(num_students - L)

全部评论

相关推荐

12-02 20:08
已编辑
门头沟学院 后端工程师
notbeentak...:孩子,说实话,选择很重要,可能你换一个方向会好很多,但是现在时间不太够了,除非准备春招
点赞 评论 收藏
分享
迷茫的大四🐶:干脆大厂搞个收费培训得了,这样就人均大厂了
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务