日渐头秃的代码日记 -- 第298场周赛第3题

108 阅读1分钟

小于等于 K 的最长二进制子序列

给你一个二进制字符串 s 和一个正整数 k 。

请你返回 s 的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k 。

注意:

  • 子序列可以有 前导 0 。
  • 空字符串视为 0 。
  • 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。

 

示例 1:

输入: s = "1001010", k = 5
输出: 5
解释: s 中小于等于 5 的最长子序列是 "00010" ,对应的十进制数字是 2 。
注意 "00100""00101" 也是可行的最长子序列,十进制分别对应 45 。
最长子序列的长度为 5 ,所以返回 5

示例 2:

输入: s = "00101001", k = 1
输出: 6
解释: "000001" 是 s 中小于等于 1 的最长子序列,对应的十进制数字是 1 。
最长子序列的长度为 6 ,所以返回 6 。

 

提示:

  • 1 <= s.length <= 1000
  • s[i] 要么是 '0' ,要么是 '1' 。
  • 1 <= k <= 10^9

解析

一个思路是先把0都提取出来,再从后向前,看看哪里可以放1,不过这样实现起来很复杂,比赛的时候一直也没写出来。 后来,老婆看了看题目,一分钟就给出来了精妙的解法。

直接从左到右看 如果k是1,就数出所有的0,再看看最后一位是不是1就行了 从左到右,用字符串p记录当前可用字符串,每一次都给p追加上当前位置的字符,看看对应二进制是否大于k,没大,保留,继续加,大了,就把坐左边的1给扔了,over。

这个方法太巧妙了,长度直增不减到最后就最大了。

class Solution:
    def remove_left_1(self, p):
        p = list(p)
        index = p.index("1")
        p.pop(index)
        return "".join(p)


    def longestSubsequence(self, s: str, k: int) -> int:
        if k == 1:
            count_0 = s.count("0")
            if s[-1] == "1":
                res = count_0 + 1
            else:
                res = count_0
            return res
        p = ""
        for index, v in enumerate(s):
            p += v
            if int(p, 2) <= k:
                continue
            else:
                p = self.remove_left_1(p)
        print(len(p), p)
        return len(p)

作者:fei-xiang-de-cheng-zi
链接:https://leetcode.cn/problems/longest-binary-subsequence-less-than-or-equal-to-k/solution/ke-neng-shi-zui-jian-dan-de-by-fei-xiang-yrr5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在执行速度上也非常快,如果把pop操作也给好好优化一下,近似于O(N)了

image.png