2022-03-11每日刷题打卡

2022-03-11每日刷题打卡

代码源——div2每日一题

01序列 - 题目 - Daimayuan Online Judge

我们称一个字符串为好字符串,指这个字符串中只包含’0’和’1’。

现在有一个好字符串,求这个字符串中’1’恰好出现k次的子串有多少个。

输入格式

第一行给出一个数字k,表示子串中’1’的个数。

第二行给出好字符串。

输出格式

输出一个整数,表示好字符串中有多少个符合条件的子串

数据范围

0≤k≤1e^6, |s|≤1e^6

样例输入1
1
1010
样例输出1
6

前缀和+哈希表。题目要求我们找的是子串中1的个数为k的情况有多少,我们当然可以枚举字串的长度,然后遍历字串的组成情况,如果满足要求则计数器++,但这样的时间复杂度为O(n^2),在这题1e6的数据下显然是会超时的,所以我们想办法把题目转化一下。既然是子串,那就说明是连续的,且字符串除了0就是1,那么我们可以用前缀和的思路来写,这样问题就变成了,区间和为k的情况有多少。我们计算子串的前缀和数组,并把相同前缀和的数量用哈希表记录下来。每一个前缀和为sum的位置,都能和所有前缀和为sum-k的位置形成好子串,所以我们计数器记录的是前缀和为sum的数量*前缀和为sum-k的数量。最后只要把计数器输出即可。

但有一种情况是特殊的,即k=0的情况,如果k=0,那么我们记录的子串数量就是前缀和为sum的情况*前缀和为sum的情况,这显然是不对的,会出现重复的好子串。所以遇到k=0时我们应该特殊处理,它的子串数为:连续ans个0组成的子串,它能形成的不同好子串为:(ans+1) * ans/2。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
#include<queue>

typedef long long ll;
typedef pair<int, int>PII;
const int MOD = 1e9 + 7;
const int N = 100100;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int k, l = 0;
    cin >> k;
    string str;
    cin >> str;
    int n = str.size();
    map<int, ll>mymap;
    mymap[0]++;
    ll res = 0;
    vector<int>v(n + 1), sum(n + 1);
    if (k == 0)
    {
        ll ans = 0;
        str += '1';
        n++;
        for (int i = 0; i < n; i++)
        {
            if (str[i] == '0')ans++;
            else
            {
                res += (ans + 1) * ans / 2;
                ans = 0;
            }
        }
    }
    else
    {
        for (int i = 1; i <= n; i++)
        {
            v[i] = str[i - 1] - '0';
            sum[i] = v[i] + sum[i - 1];
            mymap[sum[i]]++;
        }
        int ans = 0;
        while (mymap[ans + k] != 0)
        {
            res += mymap[ans] * mymap[ans + k];
            ans++;
        }
    }
    cout << res << endl;
    return 0;
}

飞书——每日一题

402. 移掉 K 位数字

给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。

示例 1 :

输入:num = “1432219”, k = 3
输出:“1219”
解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。

贪心+单调栈。贪心是,尽量去掉大的数字,而且是尽量靠前的数字,最高位的数一小,那整体肯定随着变小。

我们用单调来遍历num,当遍历到的元素大于栈顶元素时就入栈(因为我们还不知道这个算不算大,要和后面的元素比较才知道),当遍历到的元素小于栈顶元素时,说明前面的那个元素大了,我们把栈顶元素出栈,并把k–,然后继续拿那个元素和栈顶元素比,直到栈为空或者栈顶元素小于当前元素或者k为0时再把当前元素入栈。

此时栈整体呈单调增的状态,如果遍历完num后k没为0,说明还要继续删,此时只要删末尾的元素即可而不是要追求前面的元素,因为前面的已经足够小了,如果删了只会往大的方向去。之和再把字符串中栈中取出,此时字符串是逆序状态,正好让我们把前导0去掉(可能出现头部元素是0的情况,直接返回显然不对,而因为此时字符串反过来了,前导0就变成了末尾,直接pop_back即可)。最后把字符串反向后返回。

class Solution {
public:
    string removeKdigits(string num, int k) {
        int n = num.size();
        if (n == k)return "0";
        string str;
        stack<char>sta;
        sta.push(num[0]);
        for(int i=1;i<n;i++)
        {
            while(!sta.empty()&&num[i]<sta.top()&&k)
            {
                sta.pop();
                k--;
            }
            sta.push(num[i]);
        }
        while(k)
        {
            sta.pop();
            k--;
        }
        while(!sta.empty())
        {
            str+=sta.top();
            sta.pop();
        }
        while(str.size()>0&&str.back()=='0')str.pop_back();
        reverse(str.begin(),str.end());
        return str.size()==0?"0":str;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值