题解 | #合唱队#

合唱队

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-03 15:20
武汉大学 Java
点赞 评论 收藏
分享
10-31 13:04
南华大学 Java
嵌入式的小白:很多面试,面试前不会去打扰cto的,但一般cto不会在这些小事上刷人,只能说这个cto比较操心,啥重要不重要,紧急不紧急的,估计都会过问,平淡看待吧
点赞 评论 收藏
分享
青春运维少年不会梦到...:实习大王
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

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