今天去做了华为机试,两道一星题,一道二星题。
一星题 1:
题目主要大意:
输入一串字符串,里面可能包含有(x,y)的坐标。
- 0<x<1000,0<y<1000,类似(01,1)、(1,01)、(0,100)的都是非法坐标,如果字符串中找不到坐标的话返回(0,0)。
- 如果找到坐标,计算坐标 x*x+y*y的最大值,相同最大值返回第一个(x,y)。
- 不会有括号嵌套,类似asdasf((1,2))不会出现。
样例:
输入:dasd(1,2)ghdfg(3,5)ghbkk(5,10)
输出:(5,10)
输入:dasd(01,2)
输出:(0,0)
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {// 注意,如果输入是多个测试用例,请通过while循环处理多个测试用例
String str = in.nextLine();
int start = str.indexOf("(");
int end = str.indexOf(")");
int lastEnd = str.lastIndexOf(")");
if (start == -1){
System.out.println("(0,0)");
break;
}
ArrayList<MyNode> list = new ArrayList<>();
//1.查找并过滤数据
while (end !=-1){
//找到 x,y 格式数据
String temp = str.substring(start+1,end);
if (temp.length() != 0){
String[] split = temp.split(",");
if (split.length == 2){
String x = split[0]; //x
String y = split[1]; //y
int ok_x = isOK(x); //判断x是否合法,并返回合法数字
int ok_y = isOK(y); //同上判断y
if (ok_x > 0 && ok_y > 0){ //x和y都合法
MyNode node = new MyNode();
node.x = ok_x;
node.y = ok_y;
node.far = node.x * node.x + node.y * node.y;
list.add(node);
}
}
}
//字符串更新
str = str.substring(end+1);
start = str.indexOf("(");
end = str.indexOf(")");
lastEnd = str.lastIndexOf(")");
if (end == lastEnd) ++lastEnd;
}
//2.获取远距离坐标
int max=0;
int maxIndex=-1; //最大值第一次出现时的坐标
for(int i = 0; i < list.size(); i++){
MyNode myNode = list.get(i);
if (myNode.far > max){
max = myNode.far;
maxIndex = i;
}
}
if (maxIndex==-1){
System.out.println("(0,0)");
break;
}
MyNode mn = list.get(maxIndex);
System.out.println("("+mn.x+","+mn.y+")");
}
}
//传入的坐标x或者y是否符合0<s<1000,返回合法数字。
public static int isOK(String s){
if (s==null || s.length() <= 0) return -1;
char[] ch = s.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ch.length; i++) {
if(ch[0]=='0') return -1;
//下面这句是预防输入为:类似((1,2)时传入的x=(1,y=2,做过滤
if(ch[i]=='(' || ch[i] == ')') continue;
if (!(ch[i] >= '0' && ch[i] <= '9')){
return -1;
}
sb.append(ch[i]);
}
Integer num = Integer.valueOf(sb.toString());
if(num > 0 && num < 1000) return num;
return -1;
}
}
class MyNode{
int x;
int y;
int far;
}
上面的代码是100%通过了测试,43ms。
思路也很简单:
- 先从字符串里面找到所有正确的(x,y)并套用公式计算,用个对象类接收,再放入list中。
- list便利找到公式计算最大值,和最大值第一次出现的坐标,然后输出。
一星题 2:
题目大意:输入一组数字,用空格隔开,构建成完全二叉树。然后找出非叶子节点,以后序遍历方式输出。
当时没做出来,人懵逼了,不知道怎么构建一颗完全二叉树,尝试了差不多20-30分钟左右放弃了。
例子:
下午的时候百度怎么用Java构建完全二叉树,然后才做出来。
解决思路:
- 输入的字符串通过split(" ")分割成数组,可以转int,也可以直接用String。
- 构建完全二叉树
- 后序遍历时,加个判断只有当前节点的左子树不为空时才输出当前节点的值
import java.util.*;
public class Main {
public static void main(String[] args) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12};
//int arr1[] = {1, 2, 3, 4, 5, 6};
TestBinTree btree = new TestBinTree();
Node root = btree.initBinTree(arr);
Queue nodeQueue = new ArrayDeque<>();
//btree.afterTrival(root);
System.out.println("");
btree.afterTrival1(root);
//System.out.println("我们测试结果:");
//System.out.println("层序遍历:");
//btree.trivalBinTree(root, nodeQueue);
/*
System.out.println("\n先序遍历:");
btree.preTrival(root);
System.out.println("\n中序遍历:");
btree.midTrival(root);
System.out.println("\n后序遍历:");
btree.afterTrival(root);*/
}
}
/**
* 定义二叉树节点元素
*
*
*/
class Node {
public Node leftchild;
public Node rightchild;
public int data;
public Node(int data) {
this.data = data;
}
}
class TestBinTree {
/**
* 将一个arry数组构建成一个完全二叉树
*
* @param arr 需要构建的数组
* @return 二叉树的根节点
*/
public Node initBinTree(int[] arr) {
if (arr.length == 1) {
return new Node(arr[0]);
}
List<Node> nodeList = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
nodeList.add(new Node(arr[i]));
}
int temp = 0;
while (temp <= (arr.length - 2) / 2) { //注意这里,数组的下标是从零开始的
if (2 * temp + 1 < arr.length)
nodeList.get(temp).leftchild = nodeList.get(2 * temp + 1);
if (2 * temp + 2 < arr.length)
nodeList.get(temp).rightchild = nodeList.get(2 * temp + 2);
temp++;
}
return nodeList.get(0);
}
/**
* 层序遍历二叉树
*
* @param root 二叉树根节点
* @param nodeQueue ,用到的队列数据结构
*/
public void trivalBinTree(Node root, Queue<Node> nodeQueue) {
nodeQueue.add(root);
Node temp = null;
while ((temp = nodeQueue.poll()) != null) {
System.out.print(temp.data + " ");
if (temp.leftchild != null) {
nodeQueue.add(temp.leftchild);
}
if (temp.rightchild != null) {
nodeQueue.add(temp.rightchild);
}
}
}
/**
* 先序遍历
*
* @param root 二叉树根节点
*/
public void preTrival(Node root) {
if (root == null) {
return;
}
System.out.print(root.data + " ");
preTrival(root.leftchild);
preTrival(root.rightchild);
}
/**
* 中序遍历
*
* @param root 二叉树根节点
*/
public void midTrival(Node root) {
if (root == null) {
return;
}
midTrival(root.leftchild);
System.out.print(root.data + " ");
midTrival(root.rightchild);
}
/**
* 后序遍历
*
* @param root 二叉树根节点
*/
public void afterTrival(Node root) {
if (root == null) {
return;
}
afterTrival(root.leftchild);
afterTrival(root.rightchild);
System.out.print(root.data + " ");
}
//这个就是后序遍历改造,剔除掉叶子节点,只保留非叶子节点的后序遍历
public void afterTrival1(Node root) {
if (root == null) {
return;
}
afterTrival1(root.leftchild);
afterTrival1(root.rightchild);
if(root.leftchild!=null){
System.out.print(root.data + " ");
}
}
}
上面代码测试输出结果:
上面这套代码可以继续改造Node成泛型T,适配不同的数据类型。
二星题:
题目大意:
- 第一行输入n,m,k,0<n,m<100,表示n ✖️ m的地图中,可活动区域中含有最多k个敌人。
- 剩下的每行输入一串字符串,字符串中#表示墙壁,.表示可活动区域(可上下左右走),E表示敌人。
- 找出敌人数量小于k的可活动范围数量
例子:
输入:
3 5 2
..#EE
E.#E.
###..
输出:1
说明:在3✖️5的地图中,可活动区域范围最多2个敌人,需要计算可活动范围中敌人数量小于2的范围数量。