网易云音乐笔试8.8

459 阅读3分钟

1.素数的个数

给出一个包含n个正整数的数组a,把a[i]拆分为若干个和为a[i]的素数,求拆分后最多能有多少个素数。

第一行数据为n,表示数组长度,第二行为n个元素。
输入
3
1 1 1
输出
0 1不可拆分
输入
1 3 5 7
6 1为0个,3为1个,5为(2,3),7为(2,2,3)

思路:每个数除2即是答案,注意答案用long类型,int只能通过30%

package 网易0808;
import java.util.Scanner;

public class Num1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        long sum = 0;
        for (int i = 0; i < n; i++) {
            int t = scanner.nextInt();
            sum += t / 2;
        }
        System.out.println(sum);
    }
}

2.字典序最小的排列

给出一个长度为m的序列T,求一个长度为n且字典序最小的排列S,要求不改变原序列中元素的相对位置。

第一行输入两个正整数n和m
第二行输入m个数,表示序列
5 3  
2 1 5   ....T
输出
2 1 3 4 5   ....S

思路:需要找到数的个数为n-m个,首先需要枚举S中需要的元素,即S中比T中多出来的n-m个元素。如果n是5那么就需要从1开始找1.2.3... 在T中没有出现过的元素。这样就可以把T中的元素存进一个Set中,找的过程中只要在set中出现过的元素就跳过,没出现过就添加到需要的元素数组中。然后将两个数组归并排序即是答案所需要的数组。

package 网易0808;

import java.util.HashSet;
import java.util.Scanner;

public class Num2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int[] arr = new int[m];
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i < m; i++) {
            arr[i] = scanner.nextInt();
            set.add(arr[i]);
        }
        int[] need = new int[n - m];
        int index = 1;
        for (int i = 0; i < need.length; i++) {
            while (set.contains(index)) index++;
            need[i] = index++;
        }
        int i = 0, j = 0;
        index = 0;
        int[] ans = new int[n];
        while (i < arr.length && j < need.length) {
            if (arr[i] < need[j]) ans[index++] = arr[i++];
            else ans[index++] = need[j++];
        }
        while (i < arr.length) ans[index++] = arr[i++];
        while (j < need.length) ans[index++] = need[j++];
        for (int an : ans) System.out.print(an + " ");
    }
}

3.丢弃最少物品

给出n个物品,每个物品都有自己的价值,每个物品只有一件,这些物品需要分给两个人,要求分配完之后,两个人的物品价值相同。分配完成之后,会丢弃剩下的物品,求最少要丢弃多少物品。

输入
输入第一行为总的测试数据个数,第二行为物品个数n,第三行为n个物品的价值。
1
5
30 60 5 15 30
输出
20 丢弃5和15,把60分配给第一个人,2个30分配给第二个人。
(n<15)重点

思路: 刚开始做的时候想着用背包问题来解决,但是无法确定背包容量,也无法确定要丢弃的物品,没思路放弃了。这题有个很关键的条件就是n<=15,意味着用暴搜三种状态选择,1.物品分给A,2.物品分给B,3.物品分给C,那么dfs的复杂度最大为 3^15=14348907=1.4*10^8。一般只要复杂度不超过10^9都是可以AC的。所以这题直接用dfs暴搜索,做题也要注意看数量大小范围。可以看出做题的方法。

package 网易0808;

import java.util.Scanner;

public class Num3 {
    static int ans;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        for (int i = 0; i < t; i++) {
            ans = Integer.MAX_VALUE;
            int n = scanner.nextInt();
            int[] arr = new int[n];
            for (int j = 0; j < n; j++)
                arr[j] = scanner.nextInt();
            dfs(arr, 0, 0, 0, 0);
            System.out.println(ans);
        }
    }

    private static void dfs(int[] arr, int index, int sumA, int sumB, int sumDrop) {
        if (index == arr.length) {
            if (sumA == sumB) {
                ans = Math.min(sumDrop, ans);
            }
            return;
        }
        dfs(arr, index + 1, sumA + arr[index], sumB, sumDrop);
        dfs(arr, index + 1, sumA, sumB + arr[index], sumDrop);
        dfs(arr, index + 1, sumA, sumB, sumDrop + arr[index]);
    }
}

4.差距最小的生成树

给出一个无向图,一共有n个点,m条边,每条边的权值为v。 求一个生成树,使得图保持联通的同时,权值的最大值和最小值之差最小。

输入
第一行为n和m,表示点的个数和边的条数
后面为m行,表示m条边的两个顶点和其权值
3 5
1 2 10
1 3 5
3 1 12
2 3 19
1 2 74
输出
2 选择边1和3,最小差值为12-10