【上分日记】第380场周赛(数位dp+ KMP + 位运算 + 二分 + 双指针 )

news2025/6/2 10:15:24

文章目录

  • 前言
  • 正文
    • 1.3005. 最大频率元素计数
    • 2.3007.价值和小于等于 K 的最大数字
    • 3.3008. 找出数组中的美丽下标 II
  • 总结
  • 尾序

前言

 本场周赛,博主也只写出两道题(前两道, hhh菜鸡勿喷),第三道涉及位运算 ,数位dp,第四道涉及KMP。 下面我们来总结一下这四道题。

正文

1.3005. 最大频率元素计数

 这道题不难,不过有一个比较妙的写法,因此还是来分析总结一下。

  • 题目链接: 最大频率元素计数
  • 题目思路:
  1. 用一个unordered_map更新次数。
  2. 更新出最大次数时,也更新ans的初始值。
  3. 当等于最大次数时,对ans 加上 当前最大次数。
  • 关键:最大次数的出现是呈现递增趋势的.
  • 因此我们可以一边记录unordered_map, 一边更新最大次数和answer。并且一个循环就可以更新出结果。
class Solution {
public:
    int maxFrequencyElements(vector<int>& nums) 
    {
        int max_cnt = 0;
        int ans = 0;
        unordered_map<int,int> hash;
        for(auto e : nums)
        {
            if(++hash[e] > max_cnt)
                max_cnt = ans = hash[e];
            else if(hash[e] == max_cnt)
                ans += max_cnt;
        }
        return ans;   
    }
};

2.3007.价值和小于等于 K 的最大数字

  • 题目链接:价值和小于等于 K 的最大数字

  • 题目大思路:【数位dp】 / 【分类讨论 + 数学分析】 + 二分

  1. 数位dp
  1. 从高位开始枚举,一直枚举到最低位。
  2. 下一位的枚举的数字范围收到上一位的约束。
  3. 对不受到上一位约束的,采取记忆化的策略。受到上一位约束的,只有一种情况,无需记忆化。
  • 实现代码:
class Solution {
public:
    long long findMaximumNumber(long long k, int x) 
    {
         //数位dp
        auto check = [&](long long num)
        {
            //找其中为1 - num 上 x 的整数倍上 为 1的个数。
            //1.先将num转换为二进制数,到最高位即可。
            string s;
            for(int i = 0; i < 64; i++)
            {
                if(num & (1ll << (63 - i)))
                    s += "1";
                else
                    s += "0";
            }
            long long dp[64][64];
            memset(dp,-1ll,sizeof(dp));
	       /*
		       其中dp表示为枚举第 i 位,之前之前已经有j个1时,数字出现1的总数
		       1.limit表示第i位是否收到约束,即只能枚举 0 ~ s[i] - '0',
		        如果收到,下一位也要收到约束,否则可以枚举 0 ~ 9
		       2.如果枚举第i位没收到约束,且之前j个1已经求过,则无需再求,
		       即记忆化。反之,只会出现一次,没必要记忆化,当然记忆化也可以。
	       */
            function<long long(int,int,bool)> dfs = [&](int i ,\
            long long j,bool limit)
            {
                if(i == 64) return j;
                else if(!limit && dp[i][j] != -1) return dp[i][j];

                long long res = 0;
                int end = limit ? s[i] - '0' : 1;
                for(int m = 0;  m <= end; m++)
                {
                    res += dfs(i+1,j + (m == 1 && (64 - i) % x == 0),\
                    limit && (m == end));
                 /*
	                m == 1 且是x的倍数成立,结果位 j + 1,反之为 j
	                如果当前位受到限制,且枚举之后的n也达到了end,则下一位
	                受到限制。
                */
                }
                if(!limit) dp[i][j] = res;

                return res;
            };
            return dfs(0,0,true);
        };
        //二分
        long long left = 0,right = k << x;
        //找靠近右边最大的num,因此要固定右边枚举左边。
        while(left < right)
        {
            long long mid = (left + right + 1) / 2;
            if(check(mid) > k)
                right = mid - 1;
            else
                left = mid;
        }
        //必然会有答案。
        return left;
    }
};

说明:模版题——233. 数字 1 的个数

  1. 位运算 + 分类讨论
    在这里插入图片描述
class Solution {
public:
    long long findMaximumNumber(long long k, int x) 
    {
         //位运算 + 分类讨论
        auto check = [&](long long num)
        {
            long long ans = 0;
            int cnt = x - 1;
            for(long long i = num >> cnt; i; cnt += x,i >>= x)
            {
                ans += (i / 2) << cnt;
                if(i % 2)
                {
                    long long mask = (1ll << cnt) - 1;
                    ans += (num & mask) + 1;
                }
            }
            return ans;
        };
        //二分
        long long left = 0,right = k << x;
        //找靠近右边最大的num,因此要固定右边枚举左边。
        while(left < right)
        {
            long long mid = (left + right + 1) / 2;
            if(check(mid) > k)
                right = mid - 1;
            else
                left = mid;
        }
        //必然会有答案。
        return left;
    }
};
  • 补充一点:这里的right 是 最多 num 能取到的数,设为上界,具体分析跟位运算的分析雷同,看奇数位且只看最低位,即 (num / 2x-1 - 1) / 2 == k,解出上界,取一个大于 num 的即可。当然如果不想这样写,也可以直接枚举最大值作为上界。

3.3008. 找出数组中的美丽下标 II

  • 题目链接:找出数组中的美丽下标 II

  • 题目大思路:KMP + 【二分】/ 【双指针】

  • 前置知识 ——【数据结构与算法】KMP算法
  • KMP模版
vector<int> kmp(string& text,string& pattern)
{
    //求next数组
    int tsz = text.size(),psz = pattern.size();
    vector<int> next(psz);
    int index = 0;
    for(int i = 1; i < psz; i++)
    {
        char ch = pattern[i];
        while(index && ch != pattern[index])
        {
            //进行回退找最长匹配串与之匹配
            index = next[index-1];
        }
        if(ch == pattern[index])
            index++;
        next[i] = index;
    }
    vector<int> ans;
    //求子串的起始位置。
    index = 0;
    for(int i = 0; i < tsz; i++)
    {
        char ch = text[i];
        while(index && ch != pattern[index])
        {
            index = next[index-1];
        }
        if(ch == pattern[index])
            index++;
        
        if(index == psz)
        {
            //说明找到子串了,记录下标并进行回退
            ans.push_back(i + 1 - psz);
            index = next[index - 1];
        }
    }
    return ans;
};
  1. 双指针,因为要找 |j - i| <= k 的,所以我们固定 i找符合满足的 j 即可, 可以让j追i,当 j < i - k, 就让k++, 追上 i 或者 超过i 就停下。
  • 实现代码:
class Solution {
public:
    vector<int> beautifulIndices(string s, string a, string b, int k) 
    {
       
        vector<int> res;
        vector<int> pos_a = kmp(s,a);
        vector<int> pos_b = kmp(s,b);
        int asz = pos_a.size(),bsz = pos_b.size();
        int j = 0;
        for(int i = 0; i < asz; i++)
        {
            //让 j 追 i 且满足pos_b[j] < pos_a[i] - k, 就去追
            while(j < bsz && pos_b[j] + k < pos_a[i])
                j++;

            // 追上了,且满足情况
            if(j < bsz && abs(pos_a[i] - pos_b[j]) <= k)
                res.push_back(pos_a[i]);
        }
        return res;
    }
};
  1. 二分,也是固定 i , 二分找 j,因为pos_b存的是下标是递增的,因此可以二分找,我们可以找 大于等于 pos_a[ i ] 的第一个pos_b[ j ]pos_b[j - 1]可能是靠近pos_a[i]的其左边最近的那一个,对这两种情况进行讨论即可。
  • 实现代码:
   vector<int> beautifulIndices(string s, string a, string b, int k) 
   {
      
       vector<int> res;
       vector<int> pos_a = kmp(s,a);
       vector<int> pos_b = kmp(s,b);
       int asz = pos_a.size(),bsz = pos_b.size();
       for(int i = 0; i < asz; i++)
       {
           //二分找左边那个j  >= i 的最靠近的元素
           int left = 0,right = bsz - 1;
           while(left <  right)
           {
               int mid = (left + right - 1) / 2;
               if(pos_b[mid] < pos_a[i])
                   left = mid + 1;
               else
                   right = mid;
           }
           if(right >= 0 && pos_b[right] >= pos_a[i])
           {
               left = right - 1;
           }
           else
           {
               left = bsz == 0 ? -1 : right;
               right = bsz;
           }
           if( right < bsz && pos_b[right] - pos_a[i] <= k 
           || left >= 0 && pos_a[i] - pos_b[left] <= k)
           {
               res.push_back(pos_a[i]);
           } 
       }
       return res;
   }
};
  • 这里的二分,要对结果判断一下是否有效,且这里 left是 pos_b 左边最靠近 pos_a[i ] 的,right 是 pos_b右边最靠近 pos_a[i]的。
  • 推荐双指针的写法。

总结

  1. 第一道题的一种遍历写法值得品味一番。
  2. 第二道题的数位dp + 位运算 需要认真思考。
  3. 第三道题的KMP算法 的线性复杂度值得探索。
  • 彩蛋:如果存在两个题目相同,可以先把简单的AC掉,然后用难的去简单的上测试,出错是不会罚时的哦!

尾序

我是舜华,期待与你的下一次相遇!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1392559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言[]优先级大于*优先级

本博文源于笔者正在学习的c语言[]优先级大于*优先级.在定义二维数组时&#xff0c;a1与[]号结合后&#xff0c;谁的优先级更高&#xff0c;是本博文探讨的话题 博文来源 想要看看*与[]谁的优先级更高 博文代码 #include<stdio.h> #include<stdlib.h> int main(…

OAuth 2.0 - 微信登录

一、概述 1、什么是OAuth 2.0 OAuth (Open Authorization) 是一个关于授权 (athorization) 的开放网络标准。 允许用户授权第三应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方。OAuth在全世界得到广泛应用&#xff0c;目前的版本…

R语言【paleobioDB】——pbdb_orig_ext():绘制随着时间变化而出现的新类群

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_orig_ext (data, rank, temporal_extent…

核对表:基本数据类型CHECKLIST:Fundmental Data

核对表&#xff1a;基本数据类型CHECKLIST:Fundmental Data 数值概论 代码中避免使用神秘数值吗&#xff1f; 代码考虑了除零错误吗&#xff1f; 类型转换很明显吗&#xff1f; 如果在一条语句中存在两个不同类型的变量&#xff0c;那么这条语句会像你期望的那样求值吗&#x…

JMeter 相关的面试题

1、什么是 JMeter&#xff1f; 它是一个开源的负载和性能测试工具&#xff0c;用于对软件、Web应用程序、API、数据库等进行压力测试。 2、JMeter 的优势是什么&#xff1f; JMeter具有以下优势&#xff1a; 开源免费&#xff1a;JMeter是开源工具&#xff0c;无需付费使用。…

使用 Elasticsearch 和 LlamaIndex 进行高级文本检索:句子窗口检索

2023 年是检索增强生成 (RAG) 的一年&#xff0c;人们探索了许多用例&#xff0c;并使用该技术开发了数百种产品。 从 Q/A 聊天机器人到基于上下文的代理&#xff0c;RAG 的使用一直是 LLM 申请快速增长的主要因素。 支持不断发展的社区以及 Langchain 和 LlamaIndex 等强大框架…

vue-cli解决跨域

在vue.config.js中 找到devServer 在devServer中创建proxy代理 proxy:{ path&#xff08;路径中包含这个path就会导航到target的目标接口&#xff09;&#xff1a;{ target:"目标接口" } } 例&#xff1a; 1 同源策略只针对于浏览器&#xff0c;代理服务器到后端接…

如何选择适合的乔拓云小程序付费服务

在数字化时代&#xff0c;微信小程序已经成为商家与客户互动的重要平台。乔拓云小程序作为一款便捷的微信小程序&#xff0c;不仅提供免费的基本功能&#xff0c;还为商家提供了多种付费增值服务和广告投放选择&#xff0c;以满足不同需求。本文将为您揭秘乔拓云小程序的费用明…

SpringBoot多环境配置与添加logback日志

1、多环境配置 一个项目会有多个运行环境 所以SpringBoot提供了可以适应多个环境的配置文件 每个文件对应一个端口号 application-dev.yml 开发环境 端口8090 application-test.yml 测试环境 端口8091 application-prod.yml 生产环境 端口8092 在application中选择使用哪个…

中国社会科学院与新加坡社科院大学联合培养博士——如何就读在职博士

说到了在职博士&#xff0c;可能会大家就会觉得这不就是字面意思嘛&#xff1f;还用什么懂不懂的&#xff0c;在职博士的意思不就是&#xff0c;在职就是上班&#xff0c;博士就是博士&#xff0c;意思就是上班读的博士&#xff0c;当然是对的啊&#xff0c;但是知道字面意思之…

如何成为一个有趣的程序员

要成为一个有趣的程序员&#xff0c;你可以从以下几个方面着手&#xff1a; 专业技能与独特视角&#xff1a; 深入掌握至少一种编程语言&#xff0c;并了解其背后的原理和应用场景。不断学习新的编程技术、框架或工具&#xff0c;并尝试将其应用于实际项目中&#xff0c;展示你…

【基础数据结构】二叉树的基本性质

例题1 单值二叉树 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff1b;否则返回 false。 示例 1&#xff1a; 输入&#xff1a;[1,1,1,1,1,null,1] 输出&#xff1a;true示例 2&#xf…

Spring MVC学习——解决请求参数中文乱码

解决请求参数中文乱码问题 1.POST请求方式解决乱码问题 在web.xml里面设置编码过滤器 <filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><…

计算机组成原理-程序中断方式完整流程

文章目录 程序中断方式完整流程例题小结 程序中断方式完整流程 首先CPU通过执行IO指令来启动外部设备&#xff0c;此时外部设备可以开始做准备工作了&#xff08;准备CPU想要的数据或者信息&#xff09;&#xff0c;在外部设备准备过程中&#xff0c;CPU可以继续执行原程序的内…

C++初阶类与对象(一):学习类与对象、访问限定符、封装、this指针

入门知识已经梳理完毕了&#xff0c;接下来就进入到面型对象的部分学习了 文章目录 1.面向过程和面向对象初步认识2.类的引入3.类的定义3.1类的结构3.2类的两种定义方式3.2.1声明和定义全部放在类体中3.2.2声明和定义分开 3.3成员变量命名规则的建议 4.类的访问限定符及封装4.1…

python贪吃蛇游戏

为了实现这个游戏&#xff0c;需要用到Python的pygame模块&#xff0c;它是一个专门用于开发游戏的模块&#xff0c;提供了很多方便的功能&#xff0c;比如窗口、图形、音效、事件处理等。 用pygame来创建一个窗口&#xff0c;设置游戏的背景色&#xff0c;画出蛇和食物&#…

73.网游逆向分析与插件开发-背包的获取-物品数据的初步数据分析

内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;72.网游逆向分析与插件开发-背包的获取-项目需求与需求拆解-CSDN博客 然后首先找切入点&#xff1a; 通过药物来当切入点&#xff0c;药物比较好使用&#xff0c;然后鼠标放到药物上它有名字、种类、…

C++I/O流——(4)格式化输入/输出(第二节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 含泪播种的人一定能含笑收获&#xff…

美易官方:盘前:道指期货跌0.4% “恐怖数据”将发布

盘前&#xff1a;道指期货跌0.4% “恐怖数据”将发布 在今日的盘前交易中&#xff0c;道琼斯工业平均指数期货小幅下跌0.4%&#xff0c;市场正在等待即将发布的“恐怖数据”——美国零售销售数据。这一数据被视为衡量美国经济健康状况的重要指标&#xff0c;因此备受关注。 由于…

黑马程序员JavaWeb开发|案例:tlias智能学习辅助系统(6)解散部门

指路&#xff08;1&#xff09;&#xff08;2&#xff09;&#xff08;3&#xff09;&#xff08;4&#xff09;&#xff08;5&#xff09;&#x1f447; 黑马程序员JavaWeb开发|案例&#xff1a;tlias智能学习辅助系统&#xff08;1&#xff09;准备工作、部门管理_tlias智能…