华为OD机试真题---喊7的次数重排
题目描述
喊7是一个传统的聚会游戏。N个人围成一圈,按顺时针从1到N编号。编号为1的人从1开始喊数,下一个人喊的数字为上一个人的数字加1。但是,当将要喊出来的数字是7的倍数或者数字本身含有7时,不能把这个数字直接喊出来,而是要喊“过”。假定玩这个游戏的N个人都没有失误地在正确的时机喊了“过”,现在给定一个长度为N的数组,存储了打乱顺序的每个人喊“过”的次数,请把它还原成正确的顺序,即数组的第i个元素存储编号i的人喊“过”的次数。
输入输出
-
输入:
- 一行,为空格分隔的喊“过”的次数,注意K(即喊到的最大数字,但题目中并不直接给出K)不超过200,而数字的个数即为N。
-
输出:
- 一行,为顺序正确的喊“过”的次数,也由空格分隔。
示例
-
示例1:
- 输入:0 1 0
- 输出:1 0 0
-
示例2:
- 输入:0 0 0 2 1
- 输出:0 2 0 1 0
解题思路
- 读取输入:首先,读取输入的喊“过”的次数,并将其转换为整数列表。
- 计算总数:计算总的喊“过”的次数,即输入数组的和。
- 初始化变量:
- 初始化一个结果列表,用于存储每个人喊“过”的正确次数,长度与输入数组相同。
- 初始化当前数字和当前玩家索引。
- 模拟喊数过程:
- 从1开始模拟喊数的过程,直到喊“过”的次数达到总数。
- 在模拟过程中,判断当前数字是否需要喊“过”(是7的倍数或含有7)。
- 如果需要喊“过”,则减少剩余的“过”的次数,并增加当前玩家的喊“过”次数。
- 每喊完一个数,移动到下一个玩家(使用模运算实现循环)。
- 输出结果:将结果列表转换为字符串,并用空格连接后输出。
代码实现
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;public class CallSevenReordering {public static void main(String[] args) {// 创建扫描器对象以读取输入Scanner scanner = new Scanner(System.in);// 读取输入的喊“过”次数,并转换为整数数组String[] inputArrayStr = scanner.nextLine().split(" ");int[] inputArray = new int[inputArrayStr.length];for (int i = 0; i < inputArrayStr.length; i++) {inputArray[i] = Integer.parseInt(inputArrayStr[i]);}// 计算总的“过”次数int totalOvers = Arrays.stream(inputArray).sum();// 初始化结果数组,用于存储按正确顺序的喊“过”次数int[] resultArray = new int[inputArray.length];// 初始化当前数字和当前玩家索引int currentNumber = 1;int currentIndex = 0;// 模拟喊数过程while (totalOvers > 0) {// 判断当前数字是否需要喊“过”if (currentNumber % 7 == 0 || String.valueOf(currentNumber).contains("7")) {resultArray[currentIndex]++; // 当前玩家喊“过”次数加1totalOvers--; // 剩余的“过”次数减1}// 更新当前数字和当前玩家索引currentNumber++;currentIndex = (currentIndex + 1) % inputArray.length;}// 输出结果数组System.out.print(Arrays.stream(resultArray).mapToObj(String::valueOf).collect(Collectors.joining(" ")));// 关闭扫描器scanner.close();}
}
代码解析
- 读取输入:使用
input().split()
读取输入,并将其转换为整数列表a
。 - 计算总数:使用
sum(a)
计算总的喊“过”的次数s
。 - 初始化变量:
n
为玩家数量,即输入数组的长度。p
为结果列表,初始化为长度为n
的零列表。i
为当前数字,初始化为1。j
为当前玩家索引,初始化为0。
- 模拟喊数过程:
- 使用
while
循环,直到s
(剩余的“过”的次数)为0。 - 在循环中,判断当前数字
i
是否需要喊“过”。- 如果需要,则减少
s
并增加当前玩家的喊“过”次数p[j]
。
- 如果需要,则减少
- 每次循环结束后,数字
i
加1,并移动到下一个玩家(使用j = (j + 1) % n
实现循环)。
- 使用
- 输出结果:使用
join
和map
将结果列表p
转换为字符串,并用空格连接后输出。
运行实例解析
- 输入:
0 1 0
- 程序模拟喊数过程:
- 1(不过)
- 2(不过)
- 3(不过)
- 4(不过)
- 5(不过)
- 6(不过)
- 7(过,当前玩家是1,但输入说1没过,所以这是给下一个玩家的,但这里模拟是为了验证总数)
- 由于我们不知道确切的最大数,我们继续模拟直到用完所有的“过”:
- 8(不过)
- 9(不过,但当前玩家2应该在这里喊过,因为上一个7的倍数已经过了给2)
- …(继续模拟,但这里我们省略中间步骤,因为我们已经知道2会喊1次过)
- 输出:
1 0 0
(表示编号1的人喊过1次,编号2和3的人没有喊过)
注意:实际的模拟过程不需要我们确切地知道喊到了哪个数字,只需要知道每个人喊“过”的次数是否正确。由于输入已经给出了这些次数,我们的模拟主要是为了验证算法的正确性。在这个例子中,输入0 1 0
直接告诉我们答案应该是1 0 0
。