京东2017校招算法题

  • 岗位:Java 开发
  • 笔试时间:09/05/2016

第一题 购物清单

题目大意是这样的:有多组数据,每组开始给出 n 和 m (m, n ≤ 1000),n 代表价格标签的个数,m 代表要买的物品的个数,标签与物品种类一一对应。接下来一行有 n 个数,每个数代表一个价格。接着是 m 个物品名称,名称可重复出现,出现次数代表该物品购买数量。要求输出这些物品最低和最高的总价。

输入样例:

6 5
3 5 1 6 8 1
pear
apple
banana
orange
banana

输出样例:

11 30

对于样例,当 pear、apple、orange 和 banana 价格分别对应为 5、3、1、1 时,总价最低为11;价格分别对应为 3、5、6、8 时,总结最高为30。

因此,首先将物品数量降序排列,当价格升序时,将物品数量和价格从开始一一对应,得到的便是最低价;当价格降序时,将物品数量与价格一一对应,得到的便是最高价。

Java 代码如下:

import java.util.*;
public class Main {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int n, m;
        int[] val = new int[1000];
        while (sc.hasNext()) {
            n = sc.nextInt();
            m = sc.nextInt();
            for (int i = 0; i < n; ++i) {
                val[i] = sc.nextInt();
            }
            // 将物品存入 Map,Key 为物品名称,Value 为其个数
            Map<String, Integer> mp = new <String, Integer>HashMap();
            String name;
            for (int i = 0; i < m; ++i) {
                name = sc.next();
                int num = mp.getOrDefault(name, 0) + 1;
                mp.put(name, num);
            }
            // 对价格升序排序
            Arrays.sort(val, 0, n);
            List<Integer> list = new ArrayList<Integer>(mp.values());
            int size = list.size();
            Integer[] array = (Integer[])list.toArray(new Integer[size]);
            // 对物品数量升序排序
            Arrays.sort(array);
            int max = 0, min = 0;
            int i = 0;
            for (Integer num : array) {
                max += val[n - size + i] * num;
                if (size - 1 - i >= 0) {
                    min += num * val[size - 1 - i];
                }
                i++;
            }
            System.out.println(min + " " + max);
        }
    }
}

第二题 幸运数

如果一个数的二进制表示的每一位的和与其十进制表示的每一位的和相等,那么这个数就是幸运数。如十进制数123,12310 = 123,1232 = 01111011,两种表示每一位的和都是6,所以123就是一个幸运数。

输入时首先输入 t,代表数据的个数,接下来有t个数,对于每个数 n(n ≤ 1000000),输出从 1 到 n 中幸运数的个数。

输入样例:

3
1
21
22

输出样例:

1
3
3

开始我以为会有一定的规律,但是自己看了一会儿没有找到。接着想到的最快的方法就是使用一个数组保存已经计算的结果,如果后面输入的数小于等于之前的数,直接就能给出结果,就算大于之前的数,也可以利用之前计算的结果。

Java 代码如下:

import java.util.*;
public class Main {
    static int f(int n) {
        int sum = 0;
        while (n != 0) {
            sum += n % 10;
            n /= 10;
        }
        return sum;
    }
    static int g(int n) {
        int sum = 0;
        while (n != 0) {
            sum += n & 1;
            n >>= 1;
        }
        return sum;
    }
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        // 使用 buf 数组存储已经计算的结果
        int[] buf = new int[1000010];
        buf[1] = 1;
        // max 代表已经计算出的最大值
        int max = 1;
        for (int i = 0; i < t; ++i) {
            int n = sc.nextInt();
            if (n <= max) {
                System.out.println(buf[n]);
            } else {
                while (max < n) {
                    ++max;
                    // 利用前一个数的计算结果作为初始值
                    buf[max] = buf[max - 1];
                    if (g(max) == f(max)) {
                        buf[max]++;
                    }
                }
                System.out.println(buf[n]);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值