持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情
每日刷题 2022.06.21
- 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 <= 1000s[i]要么是'0',要么是'1'。1 <= k <= 109
解题思路
- 周赛的第三题,使用贪心的做法
- 分析题目:需要查找最长子序列(注:子序列是可以不连续的,通过删除原串的0~多个后得到的序列;子串是必须连续的)。
- 并且题目中还提到:子序列可以有前导
0 - 综合分析:既然可以存在前导
0,那么为了能够凑成最长的子序列,那么就将所有的0全部留下来,因为0是不会影响结果的,但是可以增长序列的长度。 - 那么接下来就需要考虑哪些
1可以留下来,哪些1需要删除- 高位的
1比低位的1代表着更大的数值,也就是说多个低位的1才能拼凑成一个高位的1,因此高位对于最长子序列的贡献,就比多个低位的1对最长子序列的贡献小。 - 总结:从低位到高位进行遍历,查看依次插入低位
1之后,是否小于等于K,找到第一个大于K的元素,那么其前一个就是最长的子序列,直接返回结果即可。
- 高位的
AC代码
/**
* @param {string} s
* @param {number} k
* @return {number}
*/
var longestSubsequence = function(s, k) {
let n = s.length, zero = 0;
// 统计原串中的0的个数,所有的0都可以用上,因为要找的是最长子序列,可以存在前导0
for(let i = 0; i < n; i++) {
if(s[i] == 0) zero++;
}
// 从低位到高位判断1,插入后是否小于等于k
let ans = 0;
for(let i = n - 1; i >= 0; i--) {
// 位置为1的时候,判断插入后的数值与K的大小
if(s[i] == 1) {
ans += Math.pow(2, n - 1 - i);
// 找到第一个大于等于K的数时,返回最长子序列长度
if(ans > k) return zero;
// console.log(Math.pow(2, n - 1 - i), k,ans)
zero++;
}
}
return zero;
};