最大战力值
问题描述
小F正在设计一款手游,游戏中的角色战力值需要根据一定规则来平衡,以提升玩家的游戏体验。现在游戏中有 n 个角色,编号从 0 到 n-1。为了保证平衡性,角色战力值需要遵循以下规则:
- 编号为
0的角色战力值初始为0。 - 每个角色的战力值必须是非负整数。
- 相邻角色的战力值差不能超过
1,即两个相邻角色的战力值差可以是0、+1或-1。
除此之外,游戏策划还为某些角色设定了最大战力值。这些限制通过若干数对给出,每一个数对 limit[i] = [index, maxPower],表示编号为 index 的角色的战力值不能超过 maxPower。这些限定只会对编号不为 0 的角色生效。
你的任务是根据上述规则和限制,计算游戏中单个角色能达到的最大战力值。
测试样例
样例1:
输入:
n = 3 ,m = 2 ,limit = [[1, 3], [2, 2]]
输出:2
样例2:
输入:
n = 5 ,m = 3 ,limit = [[1, 1], [2, 3], [4, 3]]
输出:3
样例3:
输入:
n = 4 ,m = 1 ,limit = [[2, 2]]
输出:3
解题思路
-
初始化最大战力值限制:
- 创建一个数组
maxPower,用于存储每个角色的最大战力值限制。 - 对于编号为
0的角色,其战力值固定为0。 - 对于其他角色,初始化其最大战力值为
Integer.MAX_VALUE,表示没有限制。
- 创建一个数组
-
处理限制条件:
- 遍历
limit数组,更新每个角色的最大战力值限制。
- 遍历
-
动态规划:
- 使用动态规划数组
dp,其中dp[i]表示到达第i个位置时的最大战力值。 - 初始化
dp[0]为0。 - 正向遍历数组,确保每个位置的战力值不小于前一个位置的战力值减
1,并且不超过当前位置的最大战力值限制。 - 反向遍历数组,确保每个位置的战力值不小于后一个位置的战力值减
1。
- 使用动态规划数组
-
计算最大战力值:
- 遍历
dp数组,找出其中的最大值,即为游戏中单个角色能达到的最大战力值。
- 遍历
public static int solution(int n, int m, int[][] limit) {
// 创建一个数组存储每个角色的最大战力值限制
int[] maxPower = new int[n];
for (int i = 1; i < n; i++) {
maxPower[i] = Integer.MAX_VALUE;
}
// 处理限制条件
for (int[] l : limit) {
maxPower[l[0]] = Math.min(maxPower[l[0]], l[1]);
}
// dp[i]表示到达第i个位置时的最大战力值
int[] dp = new int[n];
dp[0] = 0; // 第一个角色战力值固定为0
// 正向遍历:确保每个位置的战力值不小于前一个位置-1
for (int i = 1; i < n; i++) {
dp[i] = Math.min(dp[i - 1] + 1, maxPower[i]);
}
// 反向遍历:确保每个位置的战力值不小于后一个位置-1
for (int i = n - 2; i >= 0; i--) {
dp[i] = Math.min(dp[i], dp[i + 1] + 1);
}
// 找出最大战力值
int maxValue = 0;
for (int value : dp) {
maxValue = Math.max(maxValue, value);
}
return maxValue;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(3, 2, new int[][] { { 1, 3 }, { 2, 2 } }) == 2);
System.out.println(solution(5, 3, new int[][] { { 1, 1 }, { 2, 3 }, { 4, 3 } }) == 3);
}
}
代码解释
-
初始化最大战力值限制:
maxPower[i] = Integer.MAX_VALUE;表示初始时没有限制。maxPower[0] = 0;表示编号为0的角色战力值固定为0。
-
处理限制条件:
maxPower[l[0]] = Math.min(maxPower[l[0]], l[1]);更新每个角色的最大战力值限制。
-
动态规划:
dp[i] = Math.min(dp[i - 1] + 1, maxPower[i]);正向遍历,确保每个位置的战力值不小于前一个位置的战力值减1,并且不超过当前位置的最大战力值限制。dp[i] = Math.min(dp[i], dp[i + 1] + 1);反向遍历,确保每个位置的战力值不小于后一个位置的战力值减1。
-
计算最大战力值:
int maxValue = 0;初始化最大战力值为0。maxValue = Math.max(maxValue, value);遍历dp数组,找出其中的最大值。
最少步数归零问题
问题描述
小R拿到了一个长度为n的数组,其中每个元素都是一个正整数。小R发现每次可以删除某个数组中某个数的一位数字,这样可以逐步将所有数字变为0。他想知道,要将数组中所有数字都变为0,最少需要多少步?
例如:对于数字 103,小R可以选择删除第1位数字,将其变为 3;或者删除第2位数字,变为 13,又或者删除第3位数字,将其变为 10。最终目标是将所有数字都删除为0。
测试样例
样例1:
输入:
n = 5,a = [10, 13, 22, 100, 30]
输出:7
样例2:
输入:
n = 3,a = [5, 50, 505]
输出:4
样例3:
输入:
n = 4,a = [1000, 1, 10, 100]
输出:4
解题思路
-
将整数数组转换为字符串数组:
- 首先,我们将每个整数转换为字符串,以便于后续处理。
- 使用
String.valueOf(a[i])或Integer.toString(a[i])将整数转换为字符串。
-
去除字符串中的'0':
- 对于每个字符串,我们使用
replace("0", "")方法去除其中的'0'。 - 注意,
replace方法返回一个新的字符串,因此需要将返回值赋值回原字符串。
- 对于每个字符串,我们使用
-
计算剩余字符串的长度:
- 对于每个去除'0'后的字符串,我们计算其长度。
- 这个长度就是将该数字变为0所需的最少步数。
-
累加所有字符串的长度:
- 最后,我们将所有字符串的长度累加起来,得到将数组中所有数字变为0所需的最少步数。
public static int solution(int n, int[] a) {
int count=0;
String[] aString=new String[n];
for (int i = 0; i < n; i++) {
aString[i] = String.valueOf(a[i]); // 或者使用 aString[i] = Integer.toString(a[i]);
aString[i]=aString[i].replace("0", "");
}
for (int i = 0; i < n; i++) {
count += aString[i].length(); // 直接计算字符串长度
}
return count;
}
public static void main(String[] args) {
System.out.println(solution(5, new int[]{10, 13, 22, 100, 30}) == 7);
System.out.println(solution(3, new int[]{5, 50, 505}) == 4);
System.out.println(solution(4, new int[]{1000, 1, 10, 100}) == 4);
}
}
小S的倒序索引
问题描述
小S正在帮助她的朋友们建立一个搜索引擎。为了让用户能够更快地找到他们感兴趣的帖子,小S决定使用倒排索引。倒排索引的工作原理是:每个单词都会关联一个帖子ID的列表,这些帖子包含该单词,且ID按从小到大的顺序排列。
例如,单词“夏天”可能出现在帖子1、帖子3和帖子7中,那么这个单词的倒排链就是 [1, 3, 7]。如果用户想同时找到包含“夏天”和“海滩”的帖子,小S需要找出两个倒排链的交集,且将结果按照从大到小的顺序输出。现在,给定两个单词的倒排链数组 a 和 b,请你帮助小S找出同时包含这两个单词的帖子ID,并按从大到小的顺序返回结果。
测试样例
样例1:
输入:
a = [1, 2, 3, 7], b = [2, 5, 7]
输出:[7, 2]
样例2:
输入:
a = [1, 4, 8, 10], b = [2, 4, 8, 10]
输出:[10, 8, 4]
样例3:
输入:
a = [3, 5, 9], b = [1, 4, 6]
输出:[]
样例4:
输入:
a = [1, 2, 3], b = [1, 2, 3]
输出:[3, 2, 1]
由于 a 和 b 是有序列表,我们可以利用这一特性来优化查找交集的过程。我们可以使用双指针法来遍历两个列表,从而找到交集。
算法步骤
-
初始化指针:
- 使用两个指针
i和j,分别指向列表a和b的开始位置。
- 使用两个指针
-
遍历列表:
-
比较
a[i]和b[j]:- 如果
a[i]等于b[j],则将该元素添加到结果列表中,并将两个指针都向前移动一位。 - 如果
a[i]小于b[j],则将i向前移动一位。 - 如果
a[i]大于b[j],则将j向前移动一位。
- 如果
-
-
排序结果:
- 由于我们需要按从大到小的顺序返回结果,可以在找到交集后使用
Collections.sort(results, Collections.reverseOrder())对结果列表进行排序
- 由于我们需要按从大到小的顺序返回结果,可以在找到交集后使用
public class Main {
public static List<Integer> solution(List<Integer> a, List<Integer> b) {
List<Integer> results = new ArrayList<>();
int i = 0, j = 0;
// 使用双指针法查找交集
while (i < a.size() && j < b.size()) {
if (a.get(i).equals(b.get(j))) {
results.add(a.get(i));
i++;
j++;
} else if (a.get(i) < b.get(j)) {
i++;
} else {
j++;
}
}
// 对结果列表进行降序排序
Collections.sort(results, Collections.reverseOrder());
return results;
}
public static void main(String[] args) {
System.out.println(solution(Arrays.asList(1, 2, 3, 7), Arrays.asList(2, 5, 7)).equals(Arrays.asList(7, 2)));
System.out.println(solution(Arrays.asList(1, 4, 8, 10), Arrays.asList(2, 4, 8, 10)).equals(Arrays.asList(10, 8, 4)));
System.out.println(solution(Arrays.asList(3, 5, 9), Arrays.asList(1, 4, 6)).equals(Collections.emptyList()));
System.out.println(solution(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3)).equals(Arrays.asList(3, 2, 1)));
}
}