0
点赞
收藏
分享

微信扫一扫

给你一个数a,请你输出可能的2到16进制的结果

给你一个数a,请你输出可能的2到16进制的结果

提示:基础不牢地动山摇!!!
提示:基础不牢地动山摇!!!
提示:基础不牢地动山摇!!!
这是阿里20220407笔试手撕算法第1题
大厂笔试题经常是牛客网,然后它的代码模式往往是ACM输入模式,需要熟悉输入输出结构


文章目录


题目

给你一个数a,不知道是几进制,可能是2–16进制,请你判断它可能的进制数,并将其转化为10进制,之后mod 10^9+7,然后将一堆可能的结果排序(升序),打印这堆结果


一、笔试复盘

考试当天,这个我没有撕出来,时间不够了,最开始也没有想清楚解题思路,但是后来大概清晰之后,没时间了
考完当即复盘时的思路:应该是先判断a中是否有只有FEDCBA出现,而确定他们应该只能是16,15,14,13,12,11进制题,然后输出一个结果,其余的可能是2–16进制;——这个复盘思路也是错的。

后来我看了牛客网的帖子,终于搞懂了这个题的要领,下面说

1)做题的时候我犯了一个大错:认为java的int无法表示10^9+7,其实10位也够的!!!!
int的最大值是2147483647——于是耽误了我很多时间考虑如何求mod,实际上,只需要在每次求10进制数递增过程中直接mod即可,不影响结果的。
2)还有一个大错:在判断进制时,用了一堆if–else,去判断int数字是否有ABCDE,蠢!!!!,明明可以用java的字符串判断字符串中某一个字符,它是否是数字和字符,为啥要去枚举!!!!——显然,这里我没有搞清楚输入应该用一个字符串表达,这里我原来刷题没有用过ACM格式输入,现在开始必须熟悉这种模式。
图1
3)既然结果需要排序,自然是用有序表(treeSet),我当时一紧张,直接用了列表(List),列表到最后没法排序啊!!!!下次机智点……

4) 当时我在想,这里的如果是int a的话,32位二进制数了,每次从右往左取bit即可,也就是每次右移位运算拿bit,这个想法干扰了我做题,因为a可能出现字符,所以我用位运算取数字是不行的。

二、解题思路

本题重点在于分清最小的进制数mink,然后从最小进制数mink–16进制一起算结果就行。

注意: 无论里面有没有字符,一切a皆有可能是16进制,只不过,最小那个进制数mink取决于字符,如果是0–9,可能是2–16进制,如果是A–E,则最次有可能是11-16进制,这点要想清楚:a中包含下面字符的话
A最次就是11进制数,
B最次就是12进制数,
C最次就是13进制数,
D最次就是14进制数,
E最次就是15进制数,
F最次就是16进制数
——当理解清楚了这一点,大流程就很容易解决了。
大流程就是mink–16进制枚举×k求和转十进制数
——可惜当时我面试没有想清楚,这是基础不够硬!不过今天补足这个缺点。

笔试时,错误版本代码:

//笔试没有做出来的错误版本代码:
    public static class Main {
        public static void main_error() {
            Scanner in = new Scanner(System.in);
            // 注意 hasNext 和 hasNextLine 的区别
            int a = in.nextInt();
            List<Integer> ans = new ArrayList<>();
            int maxk = 16;
            String str = String.valueOf(a);//转化为字符串
            int flagA = str.indexOf('A');
            int flagB = str.indexOf('B');
            int flagC = str.indexOf('C');
            int flagD = str.indexOf('D');
            int flagE = str.indexOf('E');
            int flagF = str.indexOf('F');
            if (flagF != -1) maxk = 16;
            else if (flagE != -1) maxk = 15;
            else if (flagD != -1) maxk = 14;
            else if (flagC != -1) maxk = 13;
            else if (flagB != -1) maxk = 12;
            else if (flagA != -1) maxk = 11;//搞清楚是几进制
            else maxk = 16;

            for (int k = 16; k >= 2; k--) {
                //2--16进制,×k求和--题目要取模,等于没干,不需要了永远商0,得到原始结果
                //在计算机中都是二进制数01表达的,也不会超过int
                int tmp = 0;
                for (int i = 0; i < 32; i++) {
                    //最右边那个1,啥的
                    int bit = (a >> i) & 1;//取i位上的数
                    tmp += bit * k;//转为10进制数
                }
                ans.add(tmp);//加入结果
            }

            for (int i = 0; i < ans.size(); i++) {
                System.out.println(ans.get(i));
            }
        }

可见当时我的慌乱状态!
所谓基础不牢,地动山摇!!
所谓基础不牢,地动山摇!!
所谓基础不牢,地动山摇!!
就是这样。

另外还要注意,每次转k进制,是×k求和,自然少不了每次从tmp=1开始×k,然后你拿a的对应位从个位开始到高位,依次拿下来mun加上去,
如果a是字符串,则取字符减去’A’的ASCII码值+10,即转成数字,
如果a是数字,那直接减去’0’的ASCII码值,即转成数字

每次做完乘法啥的都可以直接取mod,不影响最后的结果的。

复盘之后的完整AC代码:

public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            // 注意 hasNext 和 hasNextLine 的区别
            String a = in.next();  //输入当字符串,这样方便判别是否有数字和字符
            Set ans = new TreeSet();//要求结果有序,升序排序即可

            int mink = 2;
            for (int i = 0; i < a.length(); i++) {
                char ch = a.charAt(i);
                if (Character.isDigit(ch)) mink = 2;
                else mink = Math.max(mink, 10 + ch - 'A' + 1);
            }

            int b = 1000000007;
            for (int k = mink; k <= 16; k++) {
                //mink--16进制,×k求和
                //在计算机中都是二进制数01表达的,也不会超过int
                int tmp = 1;
                int num = 0;
                for (int i = a.length() - 1; i >= 0 ; i--) {//低位开始收拾
                    //最右边那个1,啥的
                    char ch = a.charAt(i);//拿出来
                    if (Character.isDigit(ch)) num = ch - '0';//转化为数字
                    else num = ch - 'A' + 10;//字母就代表起码10上的数字

                    tmp = (k * tmp) % b + num;
                    tmp %= b;//转为10进制数mod 10^9+7
                }
                ans.add(tmp);//加入结果
            }

            for(Object i: ans) System.out.println(Integer.valueOf(i.toString()));
        }

总结

提示:参加这次笔试对于我来说是一次极为宝贵的经验:

1)让我搞清楚了牛客网的笔试输入代码格式:ACM格式,你需要搞清楚自己输入的是int呢还是字符串,这样好处理;
2)基础不牢地动山摇,平时刷了很多算法,难的,大厂高频题那些啥的,太多,非常难,但是校招的笔试1题,一定是很简单的基础,尤其是关于进制处理的题目,这些基础知识考的是你的编码能力,而不是算法优化能力;
3)第2,3题就是优化能力,这是你必须学会数据结构与算法之后,有非常敏感的算法优化能力才能做的
4)由于还有单选题,多选题,后面第3题可能没有时间干了,因此单选多选平时可能还需花点时间提前熟悉一下,尽快做完去手撕代码。

举报

相关推荐

0 条评论