持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
每日刷题 2022.10.20
- leetcode原题链接:leetcode.cn/problems/lo…
- 难度:中等
题目
- 给你一个二进制字符串 s 和一个正整数 k 。
- 请你返回 s 的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k 。
- 注意:
- 子序列可以有 前导 0 。
- 空字符串视为 0 。
- 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。
示例
- 示例1
输入:s = "1001010", k = 5
输出:5
解释:s 中小于等于 5 的最长子序列是 "00010" ,对应的十进制数字是 2 。
注意 "00100" 和 "00101" 也是可行的最长子序列,十进制分别对应 4 和 5 。
最长子序列的长度为 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
解题思路
- 倒叙遍历
s
, 酌情删除1
,同时所有的0
皆可保留。 - 证明:所有的
0
皆可以保留:- 该命题等价于, 假设题解
i
删除了位置j
上的0,那么复原位置j
的0
同时删除最大位置上的1
题解依然成立。
- 该命题等价于, 假设题解
- 容易得知,既然题解
i
成立,则位置j
一定在最大位置1
的位置右侧。同时,复原位置j
上的0
导致的净增大值,小于二倍的原最大位置1
所代表的十进制数,即小于新最大位置上1
所代表的十进制数。(参考等比数列求和) - 因此,
新十进制数 = 原十进制数 + 净增大值 - 新最大位置1代表的十进制数 < 原十进制数 <= k
。 - 所以可知,所有被删除的
0
都可以通过相同方法复原,题解依然成立,即所有的0
都不用删除
代码
/**
* @param {string} s
* @param {number} k
* @return {number}
*/
var longestSubsequence = function(s, k) {
let n = s.length, zero = 0;
for(let i = 0; i < n; i++) {
if(s[i] == 0) zero++;
}
let ans = 0;
for(let i = n - 1; i >= 0; i--) {
// if(ans > k) break;
if(s[i] == 1) {
ans += Math.pow(2, n - 1 - i);
if(ans > k) return zero;
// console.log(Math.pow(2, n - 1 - i), k,ans)
zero++;
}
}
return zero;
};