顺丰科技-Java笔试编程题-均ac
第一题:并查集
总共有m种语言,我们的并查集数组parent就是根据语言数来建立的。
对于没有任何人用过的语言,是不需要考虑的。
对于某一个人,如果其会用2种及以上的语言,那么这些语言就可以用并查集的unionTwo操作。
最后,我们的结果应该是:
对于不会任何语言的人,其至少需要学一门语言。
如果我们的并查集得到的父亲数量不为0,那么需要加上该数量减1的值。
import java.util.*;
public class Main {
private static int n; //人数
private static int m; //语言数
private static int k; //已知的信息数
private static int[] parent; //并查集
private static int[] peopleToLanguage;
private static Map<Integer, List<Integer>> peopleToLanguageMap = new HashMap<>(); //根据人将语言分群
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
m = scanner.nextInt();
k = scanner.nextInt();
peopleToLanguage = new int[n];
Arrays.fill(peopleToLanguage, -1);
parent = new int[m];
for (int i = 0; i < parent.length; i++) {
parent[i] = i; //每一种语言单独一个集合
}
boolean[] show = new boolean[m];
for (int i = 0; i < k; i++) {
int people = scanner.nextInt();
int language = scanner.nextInt() - 1;
peopleToLanguage[people - 1] = language;
if (peopleToLanguageMap.containsKey(people - 1)) {
peopleToLanguageMap.get(people - 1).add(language);
} else {
List<Integer> list = new ArrayList<>();
list.add(language);
peopleToLanguageMap.put(people - 1, list);
}
show[language] = true;
}
int result = 0;
for (int i = 0; i < peopleToLanguage.length; i++) {
if (peopleToLanguage[i] == -1) { //不会任何语言的人,肯定需要学习一种语言
result++;
}
}
for (List<Integer> list : peopleToLanguageMap.values()) {
for (int i = 0; i < list.size() - 1; i++) {
unionTwo(list.get(i), list.get(i + 1));
}
}
Set<Integer> parentSet = new HashSet<>();
for (int i = 0; i < parent.length; i++) {
if (show[i]) {
parentSet.add(findParent(i));
}
}
if (parentSet.size() != 0) {
result += parentSet.size() - 1;
}
System.out.print(result);
}
private static int findParent(int x) {
int a = x;
while (x != parent[x]) {
x = parent[x];
}
while (a != parent[x]) {
int z = a;
a = parent[a];
parent[z] = x;
}
return x;
}
private static void unionTwo(int a, int b) {
int aParent = findParent(a), bParent = findParent(b);
if (aParent != bParent) {
parent[aParent] = bParent;
}
}
} 第二题:最长非下降子序列
先来看经典的最长上升子序列问题:LeetCode——300。
本题的特殊点在于子序列中的数可以相等,没关系,自定义一个Point类,先比较数,再比较索引,复用最长上升子序列的代码即可。
import java.util.Scanner;
public class Main {
private static class Point implements Comparable {
int num;
int index;
Point(int num, int index) {
this.num = num;
this.index = index;
}
public int compareTo(Object o) {
Point p = (Point) o;
if (p.num == this.num) {
return this.index - p.index;
}
return this.num - p.num;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
Point[] points = new Point[n];
for (int i = 0; i < n; i++) {
int num = scanner.nextInt();
points[i] = new Point(num, i);
}
System.out.print(maxLengthOfRisingSubArray(points));
}
private static int maxLengthOfRisingSubArray(Point[] nums) {
int n = nums.length;
Point[] array = new Point[n];
int index = 0;
for (int i = 0; i < n; i++) {
if (i == 0) {
array[index++] = nums[i];
} else {
int ceilIndex = ceil(array, index, nums[i]);
if (ceilIndex == index) {
array[index++] = nums[i];
} else if (array[ceilIndex].compareTo(nums[i]) > 0) {
array[ceilIndex] = nums[i];
}
}
}
return index;
}
private static int ceil(Point[] array, int index, Point target) {
int left = 0, right = index;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (array[mid].compareTo(target) <= 0) {
left = mid + 1;
} else {
right = mid;
}
}
if (left - 1 >= 0 && array[left - 1].compareTo(target) == 0) {
return left - 1;
}
return left;
}
}
查看16道真题和解析