问题描述
小C参与了一场抢红包的游戏,现在他想要对所有参与抢红包的人进行一次运气排名。排名规则如下:
- 抢到的金额越多,排名越靠前。
- 如果两个人抢到的金额相同,则按照他们抢红包的顺序进行排名。
测试样例
样例1:
输入:
n = 4 ,s = ["a", "b", "c", "d"] ,x = [1, 2, 2, 1]输出:['b', 'c', 'a', 'd']
样例2:
输入:
n = 3 ,s = ["x", "y", "z"] ,x = [100, 200, 200]输出:['y', 'z', 'x']
样例3:
输入:
n = 5 ,s = ["m", "n", "o", "p", "q"] ,x = [50, 50, 30, 30, 20]输出:['m', 'n', 'o', 'p', 'q']
这道题的目标是对参与抢红包的人员进行排名,排名规则是根据抢到的总金额进行降序排列,如果金额相同,则按照他们抢红包的顺序进行排名。以下是详细的题解步骤:
题解步骤:
1. 数据结构选择:
-
使用LinkedHashMap来存储每个参与者的名字和他们抢到的总金额。
-
LinkedHashMap的选择是因为它可以保持插入顺序,这样在金额相同的情况下,参与者的顺序不会被打乱。
2. 累加金额:
-
遍历输入的名字数组s和金额数组x。
-
对于每个参与者,将其抢到的金额累加到Map中。
-
使用getOrDefault方法来处理参与者可能多次出现的情况。
3. 排序:
-
将Map的条目转换为一个List,以便进行排序。
-
使用Collections.sort对列表进行排序。
-
自定义比较器Comparator,首先根据金额进行降序排序。
4. 提取结果:
- 从排序后的列表中提取参与者的名字,形成最终的排名结果。
5. 时间复杂度:
- 主要的时间消耗在排序步骤,时间复杂度为O(n log n),其中n是参与者的数量。
代码实现:
public class Main {
public static List<String> solution(int n, List<String> s, List<Integer> x) {
// 使用Map来累加每个参与者的总金额
Map<String, Integer> participantMap = new LinkedHashMap<>();
for (int i = 0; i < n; i++) {
participantMap.put(s.get(i), participantMap.getOrDefault(s.get(i), 0) + x.get(i));
}
// 将Map转换为List以便排序
List<Map.Entry<String, Integer>> participantList = new ArrayList<>(participantMap.entrySet());
// 对列表进行排序
Collections.sort(participantList, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
// 按金额降序排序
return e2.getValue().compareTo(e1.getValue());
}
});
// 提取排序后的名字
List<String> result = new ArrayList<>();
for (int i = 0; i < participantList.size(); i++) {
result.add(i, participantList.get(i).getKey());
}
return result;
}
public static void main(String[] args) {
System.out.println(solution(4, Arrays.asList("a", "b", "c", "d"), Arrays.asList(1, 2, 2, 1)).equals(Arrays.asList("b", "c", "a", "d")));
System.out.println(solution(3, Arrays.asList("x", "y", "z"), Arrays.asList(100, 200, 200)).equals(Arrays.asList("y", "z", "x")));
System.out.println(solution(5, Arrays.asList("m", "n", "o", "p", "q"), Arrays.asList(50, 50, 30, 30, 20)).equals(Arrays.asList("m", "n", "o", "p", "q")));
}
}
问题描述
小R正在组织一个比赛,比赛中有 n 支队伍参赛。比赛遵循以下独特的赛制:
- 如果当前队伍数为 偶数,那么每支队伍都会与另一支队伍配对。总共进行
n / 2场比赛,且产生n / 2支队伍进入下一轮。 - 如果当前队伍数为 奇数,那么将会随机轮空并晋级一支队伍,其余的队伍配对。总共进行
(n - 1) / 2场比赛,且产生(n - 1) / 2 + 1支队伍进入下一轮。
小R想知道在比赛中进行的配对次数,直到决出唯一的获胜队伍为止。
测试样例
样例1:
输入:
n = 7
输出:6
样例2:
输入:
n = 14
输出:13
样例3:
输入:
n = 1
输出:0
解题思路
这个问题可以通过模拟比赛的进行来解决。我们需要计算在比赛中进行的配对次数,直到决出唯一的获胜队伍为止。
理解问题
-
初始队伍数
n:我们需要从n支队伍开始。 -
比赛规则:
- 如果队伍数为偶数,每支队伍都会与另一支队伍配对,进行
n / 2场比赛,产生n / 2支队伍进入下一轮。 - 如果队伍数为奇数,随机轮空并晋级一支队伍,其余的队伍配对,进行
(n - 1) / 2场比赛,产生(n - 1) / 2 + 1支队伍进入下一轮。
- 如果队伍数为偶数,每支队伍都会与另一支队伍配对,进行
-
目标:计算从
n支队伍到决出唯一获胜队伍为止的总配对次数。
数据结构与算法
-
数据结构:我们只需要一个整数来记录当前的队伍数
n和另一个整数来记录配对次数count。 -
算法步骤:
-
初始化
count为 0。 -
当
n大于 1 时,循环执行以下步骤:- 如果
n是偶数,进行n / 2场比赛,n变为n / 2,count增加n / 2。 - 如果
n是奇数,进行(n - 1) / 2场比赛,n变为(n - 1) / 2 + 1,count增加(n - 1) / 2。
- 如果
-
返回
count。
-
代码
public static int solution(int n) {
// write code here
int count = 0;
while (n > 1) {
if (n % 2 == 0) {
n /= 2;
count += n;
} else {
n = (n - 1) / 2;
count += n;
n++;
}
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(7) == 6);
System.out.println(solution(14) == 13);
System.out.println(solution(1) == 0);
}
}
卡牌翻面求和问题
问题描述
小M有 nn 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 aiai,背面是 bibi。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 109+7109+7 取模。
例如:如果有3张卡牌,正反面数字分别为 (1,2),(2,3) 和 (3,2),你需要找到所有满足这3张卡牌正面或背面朝上的数字之和可以被3整除的组合数。
测试样例
样例1:
输入:
n = 3 ,a = [1, 2, 3] ,b = [2, 3, 2]
输出:3
样例2:
输入:
n = 4 ,a = [3, 1, 2, 4] ,b = [1, 2, 3, 1]
输出:6
样例3:
输入:
n = 5 ,a = [1, 2, 3, 4, 5] ,b = [1, 2, 3, 4, 5]
输出:32
题目描述
小M有 (n) 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 (a_i),背面是 (b_i)。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 (10^9+7) 取模。
解题思路
-
枚举所有组合:
- 每张卡牌有两种选择(正面或背面),因此总共有 (2^n) 种可能的组合。
- 我们可以使用位运算来枚举所有组合。
-
检查每种组合的和:
- 对于每一种组合,计算所有卡牌正面或背面朝上的数字之和。
- 检查这个和是否能被3整除。
-
统计满足条件的组合数:
- 统计所有满足条件的组合数,并对结果取模 (10^9 + 7)。
代码实现
static final int MOD = 1000000007;
public static int solution(int n, int[] a, int[] b) {
int count = 0;
// 总共有2^n种可能的组合
int totalCombinations = 1 << n;
// 遍历所有可能的组合
for (int mask = 0; mask < totalCombinations; mask++) {
int sum = 0;
// 检查每一位,0表示选择正面,1表示选择背面
for (int i = 0; i < n; i++) {
if ((mask & (1 << i)) == 0) {
// 第i位是0,选择正面
sum += a[i];
} else {
// 第i位是1,选择背面
sum += b[i];
}
}
// 检查sum是否能被3整除
if (sum % 3 == 0) {
count = (count + 1) % MOD;
}
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(3, new int[]{1, 2, 3}, new int[]{2, 3, 2}) == 3);
System.out.println(solution(4, new int[]{3, 1, 2, 4}, new int[]{1, 2, 3, 1}) == 6);
System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}, new int[]{1, 2, 3, 4, 5}) == 32);
}
}
代码解释
-
枚举所有组合:
for (int mask = 0; mask < (1 << n); mask++):使用位运算mask来表示每张卡牌的选择(正面或背面)。1 << n表示 (2^n) 种可能的组合。
-
计算当前组合的和:
-
for (int i = 0; i < n; i++):遍历每张卡牌。 -
if ((mask & (1 << i)) != 0):检查mask的第i位是否为1。- 如果为
1,选择正面a[i]。 - 如果为
0,选择背面b[i]。
- 如果为
-
-
检查和是否能被3整除:
if (sum % 3 == 0):检查当前组合的和是否能被3整除。- 如果满足条件,统计该组合数,并对结果取模 (10^9 + 7)。
-
返回结果:
return count;:返回满足条件的组合数。
复杂度分析
- 时间复杂度:(O(2^n \times n)),其中 (n) 是卡牌的数量。
- 空间复杂度:(O(1)),只需要常数空间来存储中间变量。