微软20220819笔试(附JAVA代码)
感觉不是很难,等晚上笔试结束再贴一下自己的代码~
第一题
题目:
一个二维坐标系,给了两个数组X[],Y[],(X[i],Y[i])代表一个坑,现在有填坑的机器,宽度为W。每次可以沿着平行Y轴的方向修坑。问最少几次可以修完所有的坑。
思路:
类似力扣戳气球,贪心算法,每个坑都一定要修的,每次都选当前剩余的坑中第一个坑作为开始的起点x,这样以x+W以内的坑都能被修好,下次只要考虑X+W以外的坑的情况。
代码:
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.util.*;
public class Q1 {
public static void main(String[] args) {
int X[] = new int[]{2,4,2,6,7,1};
Q1 q = new Q1();
System.out.println(q.solution(X,null,2));
}
//每次第一个点都要修复,假设为i,那[i,i+W] 必然要修复,修复完考虑[i+W+1,正无穷的],又转换成刚才的问题,第一个点一定要修复
public int solution(int[] X, int[] Y, int W) {
if(X.length == 0) return 0;
Arrays.sort(X);
int end = X[0]+W;
int ans = 1;
int i = 1;
while(i < X.length){
System.out.println("当前坐标:"+X[i]+"\t当前最大值:"+end);
if(X[i]<=end){
i++;
}
else{
ans++;
end = X[i]+W;
i++;
}
System.out.println("\tans:"+ans);
}
return ans;
}
}
第二题
题目
给定一个字符串S,只由字符'0'....'9'组成,求S中字符能组成的最大的回文串。
思路
也是贪心,先计算字符串中成对的字符的个数(0要特殊处理,因为如果其他数字没成对,0成对也必要,会有前导0的问题,比如"0000"的答案应该是0,而"0011"的答案应该是1001)
因为是回文串,先拼接左边的部分,最后将字符串反转再拼接到原字符串上即可。
然后每次都选择当前能成对的字符中最大值,如果是最后一位,根据情况可以选择单个字符中的最大值。
代码
import java.util.Random;
public class Q2 {
public static void main(String[] args) {
Q2 q = new Q2();
Random r = new Random();
for (int i = 0; i < 10; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < 20; j++) {
sb.append(r.nextInt(10));
}
System.out.println(sb+":"+q.solution(sb.toString()));
}
}
public String solution(String S) {
// write your code in Java 8 (Java SE 8)
int nums[] = new int[10];
int n = S.length();
for (int i = 0; i < S.length(); i++) {
nums[S.charAt(i)-'0']++;
}
int pairs = 0;//计算相同数字的对数
for(int i = 9; i > 0; i--){
pairs+= (nums[i]/2);
System.out.println("nums["+i+"]"+nums[i]);
}
pairs+= (pairs>0? nums[0]/2 : 0);
System.out.println("nums[0]"+nums[0]);
//需要填的位数
boolean hasSingle =!(pairs*2==n);
int ansBit = pairs + (pairs*2==n?0:1);
StringBuilder ans = new StringBuilder();
for (int i = 0; i < ansBit; i++) {
for(int j = 9; j >= 0 ;j--){
if(nums[j]>=2){
ans.append(j);
nums[j]-=2;
break;
}
else if(nums[j]==1 && i==ansBit-1&&hasSingle){
ans.append(j);
nums[j]--;
break;
}
}
}
String reverse = new StringBuilder(ans).reverse().toString();
if(!hasSingle){
ans.append(reverse);
}
else{
ans.append(reverse.substring(1,reverse.length()));
}
return ans.toString();
}
}
第三题
题目
给定一个图,有N+1(0~N)个结点,N条边,任意两个结点都是联通的,现在0号结点是办公室,1到N号结点都分别住着一个人,他们都需要打车到办公室。一辆车最多可以坐5个人。每辆车每次从一个结点移动到相邻的节点都要费油1。求制定一个共乘计划,让所有的人到办公室所需的油最小。求最小油耗的值。
思路
后序遍历,从顶点和边的要求可以看出这是一棵树,问题可以转换为所有节点到根节点的最小油耗问题。要注意需要记录每个节点的人数,后面方便计算油耗。
代码
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import sun.rmi.log.LogInputStream;
import java.util.HashMap;
import java.util.*;
public class Q3 {
public static void main(String[] args) {
// int A[] = new int[]{0,1,1};
//int B[] = new int[]{1,2,3};
// int A[] = new int[]{1,1,1,9,9,9,9,7,8};
// int B[] = new int[]{2,0,3,1,6,5,4,0,0};
int A[] = new int[]{0};
int B[] = new int[]{1};
Q3 q = new Q3();
System.out.println(q.solution(A,B));
}
public int solution(int[] A, int[] B) {
// write your code in Java 8 (Java SE 8)
//建图
int N = A.length;
HashMap<Integer,List<Integer>> Graph = new HashMap<Integer, List<Integer>>();
for (int i = 0; i <= N; i++) {
Graph.put(i,new ArrayList<>());
}
for (int i = 0; i < N; i++) {
List<Integer> list = Graph.getOrDefault(A[i],new ArrayList<>());
list.add(B[i]);
Graph.put(A[i],list);
list = Graph.getOrDefault(B[i],new ArrayList<>());
list.add(A[i]);
Graph.put(B[i],list);
}
//后续遍历
int visited[] = new int[N+1];//记录每个节点是否访问过
int cnt[] = new int[N+1];//记录每个节点的人数
return postOrder(visited,Graph,0,cnt);
}
public int postOrder(int[] visited,HashMap<Integer,List<Integer>> G, int v,int cnt[]){
visited[v] = 1;
List<Integer> list = G.getOrDefault(v,new ArrayList<>());
int cost = 0;
cnt[v] = 1;
System.out.println("节点:"+v);
//到当前节点的油耗等于 其他节点到他子节点的油耗和子节点到他的油耗之和
for(int num:list){
if(visited[num]==0){
//其他节点到子节点的油耗
cost += postOrder(visited,G,num,cnt);
System.out.println("添加上子节点"+num+"所需油耗,总油耗"+cost);
//子节点到他所需的油耗
cost += (cnt[num]+4)/5;
System.out.println("添加上子节点"+num+"到"+v+"所需油耗:"+(cnt[num]+4)/5+",总油耗"+cost);
//记录当前节点的人数
cnt[v] += cnt[num];
System.out.println("添加上子节点"+num+"人数:"+cnt[num]+",总人数"+cnt[v]);
}
}
System.out.println("节点"+v+"\t耗油:"+cost+"\t人数:"+cnt[v]);
return cost;
}
}