前言
刷题之路任重而道远,革命尚未成功,同志仍需努力。由于刷惯了 LeetCode,虽然知道华为机考是需要自己输入输出,也稍稍练了一下,结果真做模拟题的时候,一下子忘了怎么获取字符串了,直接搞了个 BufferReader.readLine() 来读取字符串,麻烦的雅痞,还需要自己手动抛出异常,记录之,以下模拟题均为真实模拟题,内容来源于网络,参考链接见最后。
Scanner 输入模板:
更多内容可参考:Scanner类& 键盘中循环输入多行数组的方法
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 获取字符串
String str1 = sc.next(); // 不得输入带有空格的字符串
String str2 = sc.nextLine(); // 输入之间可以有空白,回车是结束标识符
// 获取整型数据
int n = sc.nextInt();
// 获取浮点型数据
float f = sc.nextFloat();
Double d = sc.nextDouble();
// hasNextXxx:用来判断输入的数据是否满足要求
// 例如:
while (sc.hasNextInt()){ // 此处就是通过hasNextInt方法判断输入的流是否是int类型
int a = sc.nextInt();
int b = sc.nextInt();
}
sc.close(); // 用完关掉(IO流如果不关掉就会一直占用资源)
}
}
一、Words (100分)
1、题目描述
每个句子由多个单词组成,句子中的每个单词的长度都可能不一样,假设每个单词的长度
Ni
为该单词的重量,你需要做的就是给出整个句子的平均重量V
。
输入:
输入只有一行,包含一个字符串S
(长度不会超过100),代表整个句子,句子中只包含大小写的英文字母,每个单词之间有一个空格。
输出:
输出句子S
的平均重量V
(四舍五入保留两位小数)
2、测试用例
输入: Who Love Solo
输出 :3.67
3、题解
该题是个简单题,整体思路也很清晰。由题意得,题目要求求出句子的平均重量 V,那么题目中也说了 每个单词的长度就是该单词的重量,再根据输入输出,我们很容易就知道 (平均重量V = 句子中所有单词的重量和 / 单词的个数
)。
此外,本题在CodeFun2000(2022.10.9-句子的平均重量)中有相关测试用例,可以进行在线测试。
3.1 一次遍历 – O(n) (⭐)
时间复杂度 O(n),空间复杂度 O(n)
只要理解题意,题目就很简单,根据上面的分析,我们知道了(平均重量V = 句子中所有单词的重量和 / 单词的个数
),且输入用例只有一行字符串,那么我们就直接把这行字符串存储下来,获得它的长度 len
,然后遍历这个字符串,找出字符串中空格的个数,因为每个单词之间有一个空格,那么就说明一般情况下,字符串中总的单词个数应该为 空格数+1
,那么根据这个关系我们就能很容易的写出计算公式:1.0 *(len - space) / (space + 1)
。
Note:以上分析是介于输入正确的情况下,如果输入中包含一些特殊字符,需要额外进行处理。例如:如果输入的字符串中首尾都带有空格,那么此时我们就需要使用 trim()
方法来去除字符串中的首尾空格。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine(); // 获取字符串
int len = str.length(); // 获取字符串长度
int space = 0; // 记录空格个数
for (int i = 0; i < len; i++) { // 遍历字符串
if (str.charAt(i) == ' ') // 注意charAt返回的是一个字符
space++;
}
System.out.printf("%.2f", 1.0 *(len - space) / (space + 1));
}
}
二、Vowel(100分)
1、题目描述
solo 从小就对英文字母非常感兴趣,尤其是元音字母
(a,e,i,o,u,A,E,I,O,U)
,他在写日记的时候都会把元音字母写成大写的,辅音字母则都写成小写,虽然别人看起来很别扭,但是 solo 却非常熟练。你试试把一个句子翻译成 solo 写日记的习惯吧。
输入:
输入一个字符串S(长度不会超过100,只包含大小写的英文字母和空格)。
输出:
按照 solo 写日记的习惯输出翻译后的字符串 S 。
2、测试用例
输入: Who Love Solo
输出 :whO lOvE sOlO
3、题解
题目非常清晰,一目了然,即把元音字母(a,e,i,o,u,A,E,I,O,U)
写成大写的,辅音字母则都写成小写。
3.1 一次遍历 + ASCII – O(n)(⭐)
时间复杂度 O(n),空间复杂度 O(n)
ASCII中关于数字和大小写字母的起始位要牢记(如:字符‘0’
对应的就是 48,字符‘A’
对应的是 65,字符‘a’
对应的是 97,其中‘A’ 和 ‘a’之间相差 32)
一旦我们掌握了以上的对应关系,本题就如同砍瓜切菜手到擒来。由于输入还是一个字符串,那么我们还是直接对这个字符串进行存储 str
,为了方便编程遍历操作,我们可以通过 toCharArray()
方法将字符串转成字符数组,然后对这个数组 ch 进行遍历,当遇到字符为 小写元音字母(a,e,i,o,u
)时,就将其转为大写字母,这里可以使用 ASCII值直接计算的方式实现,也可以使用 Character.toUpperCase() / Character.toLowerCase()
的方法实现(防止紧张忘记了‘A’ 和 ‘a’之间的差值是32)。字符数组遍历结束,不要忘了再把它拼接回字符串,这里我们可以使用 StringBuilder
(相较于String来拼接,StringBuilder更有效率) 来对字符数组进行拼接。
Note:System.out.println(Object)
; 会默认调用这个 object 的toString()方法,所以在以下代码中就省略掉了 StringBuilder的toString()过程,转而直接使用System.out.println(StringBuilder)。
相关内容可参考:Java字符串大小写转换
import java.util.Scanner;
public class Vowel {
public static void main(String[] args) {
// please define the JAVA input here. For example: Scanner s = new Scanner(System.in);
// please finish the function body here.
// please define the JAVA output here. For example: System.out.println(s.nextInt());
Scanner s = new Scanner(System.in);
String str = s.nextLine();
char[] ch = str.toCharArray();
for (int i = 0; i < ch.length; i++) {
if (ch[i] == 'a' || ch[i] == 'e' || ch[i] == 'i' || ch[i] == 'o' || ch[i] == 'u') {
ch[i] -= 32;
} else if (ch[i] >= 'A' && ch[i] <= 'Z') {
if (ch[i] != 'A' && ch[i] != 'E' && ch[i] != 'I' && ch[i] != 'O' && ch[i] != 'U')
ch[i] += 32;
}
}
StringBuilder sb = new StringBuilder();
for (int j = 0; j < ch.length; j++) {
sb.append(ch[j]);
}
System.out.println(sb);
}
}
三、计算字符串重新排列数(100分)
1、题目描述
给定一个只包含大写英文字母的字符串 S,要求给出对 S 重新排列的所有不相同的排列数。
如:S 为 ABA,则不同的排列有 ABA、AAB、BAA 三种。
输入:
输入一个长度不超过10的字符串S,我们确保都是大写的。
输出:
输出S重新排列的所有不相同的排列数(包含自己本身)
2、测试用例
示例 1:
输入: “ABA”
输出: 3
示例 2:
输入: “AABBCC”
输出: 90
3、题解
老生常谈的题目,求字符串的全排列,具体内容可参考:【LeetCode】剑指 Offer 38. 字符串的排列 p197 – Java Version。
3.1 回溯 – O(n!n) (⭐)
时间复杂度 O(n!n),空间复杂度 O(n2)
实现过程:
为了方便返回,我们首先定义了一个列表 res
用来存储全排列的字符串,接着通过 toCharArray()
方法将字符串转换为字符数组;定义 dfs(int idx)
方法,通过相应的控制条件实现对输入字符串长度的全排列 A(3,2) = 3! = 3 *2 *1 = 6;此外由于交换过程是可以复用的,可以写成 swap()
方法的形式;同时为了应对输入的字符串中可能含有重复的字符会导致排列形式重复的可能,可以引入 HashSet
通过contains()方法来判重,从而跳过该排列形式。
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Offer38_Permutation {
// 结果字符串存储
public static List<String> res = new LinkedList<>();
// 暂时存储
public static char[] c;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String[] strings = permutation(str);
for (String string : strings) {
System.out.printf("%s,", string);
}
}
public static String[] permutation(String s) {
if (s == "") return null;
// 将字符串转成字符数组
c = s.toCharArray();
// 全排列
dfs(0);
// 返回结果
System.out.println(res.size());
return res.toArray(new String[res.size()]);
}
public static void dfs(int idx){
// 递归终止条件: 当前字符数组固定完毕
if (idx == c.length-1){
// 将该字符串存入结果列表
res.add(String.valueOf(c));
// 结束当前递归
return;
}
// 利用HashSet给重复字符串的情况进行去重
HashSet<Character> set = new HashSet<>();
for (int i = idx; i < c.length; i++){
// 判重,如果有重复的字符,则跳过当前循环,不进行记录
if (set.contains(c[i])) continue;
set.add(c[i]);
swap(i,idx);
dfs(idx+1);
swap(i,idx);
}
}
// 交换字符数组的两个字符的位置
public static void swap(int a, int b){
char temp = c[a];
c[a] = c[b];
c[b] = temp;
}
}
四、参考资料
[1] 华为OJ-(1)word重量 &(2)元辅音大小写转换 & (3)计算字符串重新排列数
[2] 华为面试题–字符串重排