简单题总结5 | 豆包MarsCode AI刷题

103 阅读5分钟

题目描述

统计班级中的说谎者

在小C的班级里,有 N 个学生,每个学生的成绩是 A_i。小C发现了一件有趣的事:当且仅当某个学生的成绩小于或等于自己的有更多人时,这个学生会说谎。换句话说,如果分数小于等于他的学生数量大于比他分数高的学生数量,则他会说谎。

现在,小C想知道班里有多少个学生会说谎。

解题思路

这个问题主要考察数学思维。首先要理解题意,即当且仅当某个学生的成绩小于或等于自己的有更多人时,这个学生会说谎是什么意思。也就是说什么情况下会有小于等于自己的成绩的人比大于自己成绩的人更多,很容易就能看出来,我们应该首先找处于中间位置的分数作为判定条件,因为只有在这样的情况下往前或者往后才可以肯定说前后的人数不一样。同时还要弄清楚一个问题,那就是该学生本人到底是属于小于等于的那部分人,还是大于的那部分人,从测试样例中可以看出来是属于小于等于的那部分人的

所以我们的解题思路就大致明确了,首先对分数进行排序,找出中间位置的分数,就是总人数n/2位置处的分数,中间位置及之后的都是绝对属于会说谎的,那么从一开始会说谎的人数,如果是偶数就至少有总人数n/2个,奇数人数至少有总人数n/2+1个。接下来就只需要加上前面与中间位置的分数相同的人数即可。

解题代码

import java.util.Arrays;
public class Main {
    public static int solution(int[] A) {
        // Edit your code here

        //没有数不用判断
        if(A.length == 0){
            return 0;
        }
        //很明显,个数等于1那么这个人一定会说谎
        if(A.length == 1){
            return 1;
        }
        //对数组排序
        Arrays.sort(A);
        int result = 0;
        int last = A[0];
        int i = 0;
        if(A.length % 2 == 0){
            //偶数至少会有n/2个人说谎
            result += A.length/2;
            last = A[A.length/2];
            i = A.length/2-1;
            while(i>=0){
                if(A[i] != last){
                    break;
                }
                result++;
                i--;
            }
        }else{
            //奇数至少会有n/2+1个人说谎
            result += A.length/2+1;
            last = A[A.length/2];
            i = A.length/2-1;
            while(i>=0){
                if(A[i] != last){
                    break;
                }
                result++;
                i--;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        // Add your test cases here
        System.out.println(solution(new int[]{100, 100, 100}) == 3);
        System.out.println(solution(new int[]{2, 1, 3}) == 2);
        System.out.println(solution(new int[]{30, 1, 30, 30}) == 3);
        System.out.println(solution(new int[]{19, 27, 73, 55, 88}) == 3);
        System.out.println(solution(new int[]{19, 27, 73, 55, 88, 88, 2, 17, 22}) == 5);

        //System.out.println(solution(new int[]{100, 100, 100}));
        //System.out.println(solution(new int[]{19, 27, 73, 55, 88, 88, 2, 17, 22}));
    }
}

题目描述

奇妙货币交易问题

小R住在一个名为 X 国的国家,这里的货币非常特殊,面值为 V0,V1,V2,...,Vn,并且 n 可以无限大。该国的交易规则也很特别:在一次交易中,双方只能对每种面值的货币使用不超过两次。

例如,小R想买一件价格为 198 的物品,货币的基数 V=10 时,小R可以使用 2 张 100(10*10) 的纸币,卖家则找回 2 张 1(10的0次方) 的纸币。由于这个奇怪的规则,很多 X 国人都无法快速判断某个物品是否可以用这种方式交易成功,他们常常会请聪明的你来帮助。

你能帮他们判断一下,是否能按照规则用给定的货币面值 V 来完成价格为 W 的交易吗?

解题思路

这个问题我是直接探讨可能存在的不同情况来求解的。首先可以从最简单的情况看,如果价格为1或者2,那么不管货币面值为多少,该交易一定可以成功。另外如果货币面值为1,那么就更不用考虑了,它就直接可以突破在一次交易中,双方只能对每种面值的货币使用不超过两次的条件限制。因为1的n次方还是为1。

第二种情况就是,如果货币面值V大于价格W,那么只存在一种情况可以交易,那就是V-W小于等于2,否则无法交易。

第三种情况,需要先算出W模V的数,也就是用V的次方无法凑出来的那部分。对这个剩余部分进行考虑就可以,因为可以被V整除的部分一定可以至少用一张V的n次方面值给出。那么如果V与剩余值之差小于等于2,则交易可以成功。否则失败。

解题代码


public class Main {
    public static String solution(int V, int W) {
        // Edit your code here
        String result = "NO";
        if(W == 1 || W == 2 || V == 1){
            return "YES";
        }
        if(V > W){
            if(V - W <= 2){
                return "YES";
            }else{
                return "NO";
            }
        }
        int rest = W % V;
        if(rest != 0){
            if(rest == 1 || rest == 2){
                return "YES";
            }
            if(V - rest > 2){
                return result;
            }
        }
        result = "YES";

        return result;
    }

    public static void main(String[] args) {
        // Add your test cases here
        System.out.println(solution(10, 9) == "YES");
        System.out.println(solution(200, 40199) == "YES");
        System.out.println(solution(10, 9) == "YES");
        //System.out.println(solution(10, 9));

    }
}

总结

这两个问题都比较考察数学思维。关键的就是找到那个突破点,比如说统计班级说谎者中要意识到从中间位置的数开始找起,奇妙货币交易问题要从取模后剩余部分开始突破。