小红的数字删除

首先说一个概念,任意自然数N,其各位数字相加之和为M,那么N与M对模3同余。根据同余定理,可以先对N的每一位数字除以3取余,再相加后除以3取余,结果依然和N直接除以3取余相同。

举个例子1234567除以3余1,1+2+3+4+5+6+7 = 28除以3余1。分别对计算1-7除以3的余数再相加,得到1+2+0+1+2+0+1 = 7除以3余1。

这里的数学原理其实很简单,我们令个位数字是第0位,十位数字是第1位,百位数字是第2位,以此类推。假设自然数N的第i位数字是n,那么这位数字n实际代表的数是n乘以10的i次方。注意到10的i次方减去1得到999...99(i个9)必然被3整除,因此10^i 除以3必然余数是1。那么n * 10^i 与n对模3同余。相信聪明的小伙伴已经发现了,把模3改成模9,可以得到相同的结论。

好了,数学原理分析到这里,接下来开始解题。首先创建一个数组vMod,vMod[i]表示原数各位数字中除以3余数为i的个数。那么(vMod[1] + vMod[2] * 2) % 3就是原数除以3的余数,记为m。接下来具体问题具体分析。

【1】若m为0,即原数为3的倍数,那么依次去掉数字0,3,6,9这些3的倍数的数字即可,ans = vMod[0]。这里注意边界条件,若全部数字都是3的倍数,那么当剩下最后一个数字时就不能再去掉了,答案修正为ans - 1。

【2】若m不为0,即原数不是3的倍数,此时m只能是1或2。那么第一步我们需要去掉某个数,使得剩下的数满足%3 == 0的条件,接下来再依次去掉数字0,3,6,9这些3的倍数的数字即可,ans = vMod[0] + 1。注意!!!这里去掉的某个数可能并不存在,此时ans = 0。判断的依据就是vMod[m]的值是否大于0。举个例子119999,这里的m = 2,vMod[2] = 0,因此答案为0。

然后我们再分析【2】的边界条件。这里就比较恶心了,有2个边界条件。第一个条件和【1】中类似,若最后ans等于原数各位数字的个数,那么当剩下最后一个数字时就不能再去掉了,答案修正为ans - 1;第二个条件,若vMod[m] = 1,且对应的数字正好是原数的最高位数字,就要考虑前导0的情况。举例2001497,这里m = 2,第一次去除数字只能去除最高位2,此时该数字就变成了1497,还能再删除9,最终ans = 2。观察发现vMod[0] + 1 = 4,和ans正好相差2,这个数字正好是最高位去掉后前导0的个数。因此这种情况下ans = vMod[0] + 1 - 最高位后前导零个数。

好了,大功告成,提交~

结果……没有AC。

原因是,当【2】的两个边界条件结合起来时,情况又会发生变化。举例数字10003,根据公式前导零个数为3,因此ans = vMod[0] + 1 - 3 = 2。实际情况是,ans = 1,当首位的1去除后,剩下数字是3,不能再去除了。类似的数字2000,使用公式计算ans = 1,而实际ans = 0。

找到问题后就简单了,首先ans = vMod[0] + 1,判断ans的值是否等于原数各位数字的个数,若是则修正ans = ans - 1。接下来再判断vMod[m] = 1,且对应的数字正好是原数的最高位数字的情况,ans = ans - 最高位后前导零个数。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int t;
    cin >> t;
    string n;
    while (t--) {
        cin >> n;
        vector<int> vMod(3, 0);//vMod[i]表示原数各位数字中除以3余数为i的个数
        for (char& c : n) {
            ++vMod[(c - '0') % 3];
        }
        int m = (vMod[1] + vMod[2] + vMod[2]) % 3; //原数除以3的余数
        int ans;
        if (m == 0) { //原数为3的倍数
            ans = vMod[0];
            if (ans == n.size()) --ans;
        } else { //原数不是3的倍数
            if (vMod[m] == 0) {   //没有任何一位数字跟原数模3同余
                ans = 0;
            } else {
                ans = vMod[0] + 1; //先删掉同余数字,再删余数为0的
                if (ans == n.size()) --ans;
                if (vMod[m] == 1 && (n[0] - '0') % 3 == m) {
                    for (int i = 1; i < n.size(); ++i) {
                        if (n[i] != '0') break;
                        --ans;
                    }
                }
            }
        }
        cout << ans << endl;
    }
}

作者:君鸿

链接:https://www.nowcoder.com/discuss/698256981756215296

来源:牛客网

全部评论

相关推荐

06-15 00:30
已编辑
门头沟学院 Java
昨天晚上收到电话的面试邀约很激动,也很害怕,害怕自己抓不住机会,但是面试的时候面试官超级好,人特别好,有不会的面试官会给你提示,同时还会给你肯定的回应。下面是一些面试经历:💻面试岗位:java后端开发❓面试问题:JVM:1.JVM的内存模型以及垃圾回收5个内存模型+4种回收算法2.JVM的内存模型中哪些是共享的,哪些是私有的集合:1.看过哪些集合的源码?答:看过ArrayList2.根据你看过的源码,讲述一下add()方法的3.在项目中你会用ArrayList储存一个经常变动的数据吗?4.map顶层的接口实现类有哪些?(答:HashMap的一些底层原理)5.HashMap的put方法介绍一下并发编程:1.锁的介绍,你用什么锁?介绍一下(项目中的悲观锁锁表,乐观锁)2.对Syconized和lock的区别?3.Synchronized的锁升级机制?4.偏向锁(可重入锁,有个标记点),轻量级锁实际是怎么实现?5.线程池你有用到过吗?(项目中的逻辑过期用到的线程池)6.你用到的线程池你是自己定义的还是线程池自带的?(自带的线程池,队列的最大值是自己设置的,会消耗内存)7.线程池你是自己自定义的,你是怎么考虑的,线程的核心线程数,最大线程数,阻塞队列?框架:1.spring,springBoot,springcloud他们之间的关系,你可以讲述一下吗?2.概述一下spring&nbsp;IOC和Aop3.单例的循环依赖简述一下?(三级缓存)数据库:1.数据库的范式概述一下?(我说了三大范式,面试官补充说现在已经不止三大范式了,变成5个了)2.Mysql的基本调优你有接触过吗?(讲到了索引失效)3.什么情况索引失效?4.我更想知道你调节SQL的时候你发现比较慢,你会怎么一步步发现慢在哪一点?(排查SQL,数据库执行的排查计划)项目:1.两个项目中你哪个项目中参与比较深?2.项目中遇到的问题和项目中的亮点?(开放性思维)3.项目中你用到了redission,你对什么进行加锁的,是某个对象还是某个标识(库存行id)?🙌面试感想:面试之前很紧张,也没想过能过,就当是一次经验,面试官人很好,给了很多建议,关于八股这些,让我多看,多整理一下代码的底层原理。最后告诉我,在他那我算是过了,之后还有主管面,HR面,最后他和我说,他这里不是菜鸟的正式岗位,是什么红林计划?执管岗位,不是菜鸟正式岗位,当时没记太清,也没问清楚,之后主管面要是过了的话,再问问,希望后面的面试顺利吧。
半夏夏柳:跟我面的同一个菜鸟外包,面的人估计都一样😂
查看24道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务