【 面试 Java 】华为机试真题总结

一、进制转换

写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。

背景知识: 16进制以0x开头,后面跟数字0 ~ 9或字母A ~ F(小写也可以

解法一 : API 法

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String a = in.nextLine();
        // 去掉表示十六进制的 0x 前缀 —— 从而使得我们可以使用下面的 API 实现进制转换
        a = a.substring(2);
        // 实现进制转换的两种 API
        // int ans = Integer.valueOf(a, 16);
        int ans = Integer.parseInt(a, 16);
        System.out.println(ans);
    }

解法二: 自己实现 API 法

思路很简单,就类似于给你一个 10 进制的字符串,如何整合成 10 进制数字 。 都是从后向前遍历,取出每一位,然后整合在一起。

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String a = in.next();
        a = a.substring(2);
        int n = a.length();
        int ans = 0;
        int base = 1;
        for(int i=n-1; i>=0; i--){
            // 当前位的值
            int num;
            // 取出当前位, 并且转为大写
            int curChar = Character.toUpperCase(a.charAt(i));
            if(curChar >= '0' && curChar <= '9'){
                num = curChar - '0';
            } else {
                num = 10 + curChar - 'A';
            }
            ans += num * base;
            base *= 16;
        }
        System.out.println(ans);
    }
}

二、 字符串最后一个单词的长度

计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String a = in.nextLine();
        int ans = 0;
        int idx = a.length() - 1;
        while(idx != -1 && a.charAt(idx) != ' '){
            idx--;
            ans++;
        }
        System.out.println(ans);
    }

注: 为什么不用 split 法, 因为占用太多额外的空间了,所以不用 API 了 (虽然我是最懒懒喜欢用 API 的人,但是这种占用太多额外空间的,而且明显有更优解法的,咱就不用了)

三、坐标移动

开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。

字符串类型题,主要考查点在于字符串处理函数,加上循序渐进的思考能力

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    
    public boolean isEffective(String str) {
        if(str.isEmpty() || str.length() > 3){
            return false;
        }
        String direction = "ADWS";
        if(direction.indexOf(str.charAt(0)) == -1) {
            return false;
        }
        for(int i=1; i<str.length(); i++){
            if(!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        String a = in.nextLine();
        String[] strs = a.split(";");
        int x = 0;
        int y = 0;
        for(String str : strs) {
            // 先判断是否无效
            if(!main.isEffective(str)){
                continue;
            }

            // 有效进行处理
            char direction = str.charAt(0);
            int step = Integer.parseInt(str.substring(1));
            if(direction == 'A'){
                x -= step;
            } else if(direction == 'D'){
                x += step;
            } else if(direction == 'W'){
                y += step;
            } else {
                y -= step;
            }
        }
        System.out.println(x + "," + y);
    }
}

四、密码验证合格程序

吐血 …

总结反思 : 没必要写这么长,没必要那么多标注位,拆成函数解决,就 ok 了

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextLine()) { 
            String pas = in.nextLine();
            if(pas.length() <= 8){
                System.out.println("NG");
                continue;
            } 
            boolean over = false;
            // 每位标志分别表示 大写字母,小写字母 , 数字, 其他符号
            int[] flag = new int[4];
            for(int i=0; i<pas.length(); i++){
                char cur = pas.charAt(i);
                if(cur == ' ' || cur == '\n' ){
                    over = true;
                    break;
                }
                if(Character.isDigit(cur)){
                    flag[0] = 1;
                } else if(Character.isLowerCase(cur)){
                    flag[1] = 1;
                } else if(Character.isUpperCase(cur)){
                    flag[2] = 1;
                } else {
                    flag[3] = 1;
                }
                // 说明已经凑齐了
                if(Arrays.stream(flag).sum() >= 3){
                    break;
                }
            }
            // 包含空格和换行符,不满足题意
            if(over){
                System.out.println("NG");
                continue;
            }
            // 没凑齐,是不满足题意的
            if(Arrays.stream(flag).sum() < 3){
                System.out.println("NG");
                continue;
            }
            Set<String> set  = new HashSet();
            for(int i=0; i<pas.length()-1; i++){
                for(int j=i+2; j<pas.length(); j++){
                    String subStr = pas.substring(i, j+1);
                    if(set.contains(subStr)){
                        over = true;
                        break;
                    }
                    set.add(subStr);
                }
            }
            if(over){
                System.out.println("NG");
            } else {
                System.out.println("OK");
            }
        }
    }
}

五、整数与IP地址间的转换

原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成一个长整数。

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        String ip = in.nextLine();
        String numStr = in.nextLine();
        System.out.println(main.IpToNum(ip));
        System.out.println(main.NumToIp(Long.parseLong(numStr)));
    }


    // 数字转 Ip 地址
    public String NumToIp(Long num){

        // 转换为 二进制 字符串
        String biNum = Long.toBinaryString(num);
        int len = biNum.length();
        // 用于拼接整合结果
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<32-len; i++){
            sb.append("0");
        }
        sb.append(biNum);
        // 每八位加入一个 "."
        sb.insert(8, ".");
        sb.insert(17, ".");
        sb.insert(26, ".");

        String biAn = new String(sb);
        String[] strs = biAn.split("\\.");
        int[] reduce = Arrays.stream(strs).mapToInt(string -> Integer.parseInt(string, 2)).toArray();
        String ans = "";
        for(int i=0; i<4; i++){
            ans += reduce[i];
            if(i != 3){
                ans += ".";
            }
        }
        return ans;
    }

    public Long IpToNum(String ip){
        String[] strs = ip.split("\\.");
        String ans = "";
        // 组合 ans
        for(int i=0; i<4; i++){
            String cur = strs[i];
            int num = Integer.parseInt(cur);
            String biNum = Integer.toBinaryString(num);
            int zeroNums = 8 - biNum.length();
            while(zeroNums > 0){
                biNum = "0" + biNum;
                zeroNums--;
            }
            ans += biNum;
        }
        // 把 ans 转为 10 进制
        Long ansNum = Long.parseLong(ans, 2);
        return ansNum;
    }
}

六、矩阵乘法计算量

矩阵乘法的运算量与矩阵乘法的顺序强相关。
例如:
A是一个50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵
计算ABC有两种顺序:((AB)C)或者(A(BC)),前者需要计算15000次乘法,后者只需要3500次。

编写程序计算不同的计算顺序需要进行的乘法次数。

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int num = Integer.parseInt(in.nextLine());
        int[][] arr = new int[num][2];
        for(int i=0; i<num; i++){
            String[] cur = in.nextLine().split(" ");
            arr[i][0] = Integer.parseInt(cur[0]);
            arr[i][1] = Integer.parseInt(cur[1]);
        }
        int ans = 0;
        String str = in.nextLine();
        Stack<int[]> stack = new Stack<>();
        for(int i=0; i<str.length(); i++){
            if(str.charAt(i) == '('){
                // stack.push('(');
            } else if(str.charAt(i) == ')'){
                // 出栈,找到对应的右括号
                int[] B = stack.pop();
                int[] A = stack.pop(); 

                ans += A[0] * A[1] * B[1];
                // stack.pop();
                // 放入计算结果
                stack.push(new int[]{A[0], B[1]});
                
            } else {
                stack.push(arr[str.charAt(i)- 'A']);
            }
        }
        System.out.println(ans);
    }
}

七、输出所有可能的栈序列

注: 本题的关键在于 栈序列 最后输出的顺序 …

import java.util.*;


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    List<List<Integer>> ans = new ArrayList<>();
    public static void main(String[] args) {
        Main main = new Main();
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别

        int num  = Integer.parseInt(in.nextLine());
        String sort = in.nextLine();
        String[] sortArr = sort.split(" ");
        int[] pushArr = new int[num];
        for (int i = 0; i < num; i++) {
            pushArr[i] = Integer.parseInt(sortArr[i]);
        }

        List<Integer> list = new ArrayList<>();
        boolean[] used = new boolean[num];
        // 输出以字典序从小到大排序的火车出站序列号
        List<String> ansString = new ArrayList<>();

        // 得到所有组合数
        main.getAll(num, pushArr, list, used);
        for (int i = 0; i < main.ans.size(); i++) {
            List<Integer> list1 = main.ans.get(i);
            if (main.canGet(list1.stream().mapToInt(a -> a).toArray(), pushArr)) {
                StringBuilder sb = new StringBuilder();
                for (int k = 0; k < num; k++) {
                    sb.append(list1.get(k) + "");
                    if(k != num){
                        sb.append(" ");
                    }
                }
                ansString.add(String.valueOf(sb));
            }
        }
        Collections.sort(ansString);
        for(int i=0; i<ansString.size(); i++){
            System.out.println(ansString.get(i));
        }

    }

    public void getAll(int n, int[] arr, List<Integer> list, boolean[] used) {
        if (list.size() == n) {
            ans.add(new ArrayList<>(list));
            return;
        }
        for (int i = 0; i < n; i++) {
            if (!used[i]) {
                used[i] = true;
                list.add(arr[i]);
                getAll(n, arr, list, used);
                list.remove(list.size() - 1);
                used[i] = false;
            }
        }
    }

    public boolean canGet(int[] popArr, int[] pushArr) {


        // 用栈来进行模拟
        Stack<Integer> stack = new Stack<>();
        // j 表示当前遍历到的出栈位置
        int j = 0;
        for (int i = 0; i < pushArr.length; i++) {
            stack.push(pushArr[i]);
            while (!stack.isEmpty() && (j < popArr.length && stack.peek() == popArr[j]) ) {
                stack.pop();
                j++;
            }
        }
        return stack.isEmpty();
    }
}

八、字符串转换

将输入的字符串(字符串仅包含小写字母‘a’到‘z’)按照如下规则,循环转换后输出: a->b,b->c,…,y->z,z->a;

  1. 若输入的字符串连续出现两个字母相同时,后一个字母需要连续转换2次。例如:aa 转换为 bc,zz 转换为 ab;
  2. 当连续相同字母超过两个时,第三个出现的字母按第一次出现算。

翻译

对连续的字母,奇数位置上的转换两次,偶数上的位置按照原始位置转换 1 次

思路

  1. 先统一转换一次
  2. 形如 bb 形式的再转换一次 , 然后直接跳两个位置,再找形如 bb 形式的
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 得到该字符串
        String string = in.next();
        char[] stringArr = string.toCharArray();

        // 统一转换第一次
        for (int i=0; i<stringArr.length; i++){
            if(stringArr[i] == 'z'){
                stringArr[i] = 'a';
            } else {
                stringArr[i] = (char) ((int)stringArr[i] + 1);
            }
        }
        // 第二次遍历,对形如 aa 形式的再次转换,因为第三个出现的按照第一次的转换,所有直接跳 2
        for (int i=1; i<stringArr.length; i++){
            if(stringArr[i] == stringArr[i-1]) {
                if(stringArr[i] == 'z'){
                    stringArr[i] = 'a';
                } else {
                    stringArr[i] = (char) ((int)stringArr[i] + 1);
                }
                i += 1;
            }
        }
        System.out.println(new String(stringArr));
    }

九、HJ14 字符串排序

给定 n 个字符串,请对 n 个字符串按照字典序排列。

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int length = in.nextInt();
        String[] strs = new String[length];
        int i = 0 ;
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            String a = in.next();
            strs[i] = a;
            i++;
        }
        Arrays.sort(strs);
        for(int j=0; j<length; j++){
            System.out.println(strs[j]);
        }
    }
}

十、查找两个字符串a,b中的最长公共子串

查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!

思路 :

动态规划

  1. dp 数组表示以 i,j 位置结尾的子串长度
  2. dp 初始化
  3. 状态转移
if(strs1[i] != strs2[j]){
	dp[i][j] = 0;
} else {
	dp[i][j] = dp[i-1][j-1]  + 1;
}
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        String a = in.next();
        String b = in.next();
        int aLen = a.length();
        int bLen = b.length();
        if(aLen > bLen){
            String temp = a;
            a = b;
            b = temp;
            int tempNum = aLen;
            aLen = bLen;
            bLen = tempNum;
        }
        char[] aStr = a.toCharArray();
        char[] bStr = b.toCharArray();
        // dp 数组表示以 (i, j)结尾的相同子字符串的最长长度
        int[][] dp = new int[aLen][bLen];

        int max = 0;
        String temp = "";
       

        for(int i=0; i<aLen; i++){
            for(int j=0; j<bLen; j++){
                if(aStr[i] == bStr[j]){
                    if(i != 0 && j != 0){
                        dp[i][j] = dp[i-1][j-1] + 1;
                    } else {
                        dp[i][j] = 1;
                    }
                }
                if(dp[i][j] > max){
                    max = dp[i][j];
                    temp = b.substring(j+1-max, j+1);
                } 
            }
        }

        System.out.println(temp);
    }
}

十一、计算某字符出现的次数

写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字符,然后输出输入字符串中该字符的出现次数。(不区分大小写字母)

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        String str = in.nextLine();
        String temp = in.nextLine();
        Character target = temp.charAt(0);
        int res = 0;
        for(int i=0; i<str.length(); i++){
            if(Character.toUpperCase(target) == Character.toUpperCase(str.charAt(i))){
                res++;
            }
        }
        System.out.println(res);
        
    }
}

注意: 用 nextLine 接收输入,因为可能空格,以后接收一行我们都用 nextLine

十二、字符统计

统计字符串中含多少字符 (0 ~ 127 范围)

public class CharacterStatistic {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        Set<Character> set = new HashSet();
        char[] strArr = str.toCharArray();
        for (int i=0; i<strArr.length; i++){
            if(strArr[i]>=0 && strArr[i]<=127) {
                set.add(strArr[i]);
            }
        }
        System.out.println(set.size());
    }
}

十三、质数因子

输出一个数的所有质数因子。

对本题, 我们要明确一点: 所有的合数都能由比其更小的质数的乘积表示 。即:当我们除 4 时, 早就被 2 这个质数过滤掉了 。

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        long a = in.nextLong();
        for(int i=2; i<=Math.pow(a, 0.5); i++){
            while(a % i == 0){
                System.out.print(i + " ");
                a /= i;
            }
        }
        if(a != 1){
            System.out.println(a);
        }
    }
}

十四、组成直角三角形的个数

有N条线段,长度分别为a[1]-a[N]。现要求你计算这N条线段最多可以组合成几个直角三角形,每条线段只能使用一次,每个三角形包含三条线段。

 输入: 
 1 
 7 3 4 5 6 5 12 13 
 输出: 
 2 
 说明: 可以组成2个直角三角形(3,4,5)、(5,12,13) 

翻译:就是求满足题意的组合数量

import java.util.function.ToIntFunction;

/**
 * @author wanqingLiu
 * @date 2023/3/20 13:47
 */
public class RightTriangleNum {
    public static final int SIDE_NUMBER = 3;
    static int res = 0;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 得到数据组数 n
        int N = Integer.parseInt(scanner.nextLine());
        while (N != 0) {
            String cur = scanner.nextLine();
            String[] strs = cur.split("\\ ");
            int[] nums = Arrays.stream(strs).mapToInt(value -> Integer.parseInt(value)).toArray();
            int n = nums[0];
            int[] numsTemp = new int[n];
            for (int i = 0; i < n; i++) {
                numsTemp[i] = nums[i + 1];
            }
            Arrays.sort(numsTemp);
            boolean[] idxs = new boolean[n];
            // 对 nums 回溯求满足题意的组合数(就是满足勾股定理的组合)
            backTrace(new ArrayList<>(), numsTemp, n, 0, idxs);
            System.out.println(res);
            res = 0;
            N--;
        }
    }

    // 如何避免重复 —— 记录 index 的数组, 然后将用过的 index 设置为下次不容许使用
    public static void backTrace(List<Integer> list, int[] nums, int n, int startIndex, boolean[] idxs) {
        if (list.size() > SIDE_NUMBER) { // 剪枝操作
            return;
        }
        // 用过的不能再用 , 标记用过
        if (list.size() == SIDE_NUMBER && isRightTriangle(list, nums)
                && !idxs[list.get(0)] && !idxs[list.get(1)] && !idxs[list.get(2)]) {
            idxs[list.get(0)] = true;
            idxs[list.get(1)] = true;
            idxs[list.get(2)] = true;
            res++;
            return;
        }
        for (int i = startIndex; i < n; i++) {
            if (!idxs[i]) { // 每个边只能用一次
                list.add(i);
                backTrace(list, nums, n, i + 1, idxs);
                list.remove(list.size() - 1);
            }
        }
    }

    /*
    勾股定理判断是否可组成直角三角形
     */
    public static boolean isRightTriangle(List<Integer> list, int[] nums) {
        Collections.sort(list);
        int a = nums[list.get(0)];
        int b = nums[list.get(1)];
        int c = nums[list.get(2)];
        return (a * a + b * b) == c * c;
    }
}

ps: 调代码调到吐血 , QWQ ~~~

十五、最大漂亮度

import java.util.*;

// 思路:map 记录每个单词出现的次数,按出现次数从大到小,赋予漂亮度
// 涉及到 map 排序问题
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = Integer.parseInt(in.nextLine());
        
        while (N != 0) { // 注意 while 处理多个 case
            String cur = in.nextLine();
            Integer[] charNum = new Integer[26];
            Arrays.fill(charNum, 0);
            for(int i=0; i(o2-o1));
            int ans = 0;
            int temp = 26;
            for(int i=0; i<26; i++){
                if(charNum[i] == 0){
                    break;
                }
                ans += charNum[i] * temp;
                temp--;
            }
            System.out.println(ans);
            N--;
        }
    }
}

你可能感兴趣的:(Java,面试,java,算法)