数字分组求偶数和
1. 问题描述
小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。
numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。
例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369。
2. 测试样例
样例1:
输入:
numbers = [123, 456, 789]
输出:14
样例2:
输入:
numbers = [123456789]
输出:4
样例3:
输入:
numbers = [14329, 7568]
输出:10
3. 解题思路
要从每个数字组中选择一个数字,使得这些数字的和为偶数。问题可以主要拆解为两部分内容:
- 奇偶性:一个数是偶数当且仅当它的各位数字之和为偶数;
- 组合生成:我们需要生成所有可能的组合,并检查这些组合的和是否为偶数。
换言之,需要使用递归或迭代的方式来生成所有可能的组合,并且利用一个布尔数组来记录每个数字组中选择的数字是否为偶数。
算法步骤:
-
递归生成组合:
- 对于每个数字组,选择一个数字;
- 递归地处理下一个数字组;
- 当处理完所有数字组时,检查当前组合的和是否为偶数。
-
检查和的奇偶性:
- 如果当前组合的和为偶数,则计数加一。
4. 代码
public class Main {
public static int solution(int[] numbers) {
// 初始化计数器
int count = 0;
// 生成组合
count = fab(numbers, 0, 0, count);
return count;
}
// 递归生成组合
private static int fab(int[] numbers, int index, int currentSum, int count) {
// 如果已经处理完所有数字组
if (index == numbers.length) {
// 检查当前组合的和是否为偶数
if (currentSum % 2 == 0) {
count++;
}
return count;
}
// 获取当前数字组
int currentGroup = numbers[index];
// 遍历当前数字组中的每个数字
while (currentGroup > 0) {
int digit = currentGroup % 10;
// 递归处理下一个数字组
count = fab(numbers, index + 1, currentSum + digit, count);
currentGroup /= 10;
}
return count;
}
public static void main(String[] args) {
// 测试用例
System.out.println(solution(new int[]{123, 456, 789}) == 14);
System.out.println(solution(new int[]{123456789}) == 4);
System.out.println(solution(new int[]{14329, 7568}) == 10);
}
}
数组元素之和最小化
1.题目描述
小C希望构造一个包含n个元素的数组,且满足以下条件:
- 数组中的所有元素两两不同。
- 数组所有元素的最大公约数为
k。 - 数组元素之和尽可能小。
任务是输出该数组元素之和的最小值。
2.测试样例
样例1:
输入:
n = 3 ,k = 1
输出:6
样例2:
输入:
n = 2 ,k = 2
输出:6
样例3:
输入:
n = 4 ,k = 3
输出:30
3.解题思路
最大公约数为k,只需要以k的倍数从小到大构造数组即可得到元素和的最小值。
4.代码
public static int solution(int n, int k) {
int sum = 0;
for (int i = 1; i <= n; i++) sum += k * i;
return sum;
}
基本字符串转换
1.题目描述
小U正在研究字符串的转换问题。他发现一个由字母 'a' 组成的字符串被称为“基本”字符串。现在给定一个长度为N的字符串S,该字符串中的字符从0到N-1进行编号。在每次操作中,你可以选择三个索引i、j和k,其中i < j < k,并且满足 S[i] 和 S[k] 都是 'a',然后你可以将 S[j] 的字符也设置为 'a'。
你的任务是判断是否可以通过多次执行该操作,将字符串S变为一个基本字符串。如果可以,将返回 1;否则返回 0。
2.测试样例
样例1:
输入:
N = 7, S = "aaacaaa"
输出:True
样例2:
输入:
N = 5, S = "ababa"
输出:True
样例3:
输入:
N = 6, S = "aaaaab"
输出:False
3.解题思路
题目要求我们判断能不能通过操作把一个字符串转变成基本字符串,仔细研究这个操作可以发现
i和k之间的字符都可以设置成a,因此只需要确定第一个字符和最后一个字符是否都是a,就可以判断字符串能否转成一个基本字符串。
4.代码
public class Main {
public static boolean solution(int N, String S) {
int len = S.length();
if(S.charAt(0)=='a' && S.charAt(len-1)=='a') return true;
return false;
}
public static void main(String[] args) {
System.out.println(solution(7, "aaacaaa") == true);
System.out.println(solution(5, "ababa") == true);
System.out.println(solution(6, "aaaaab") == false);
}
}
小U的地板砖之旅
1. 问题描述
小U有 n 块地砖,她需要从第一块地砖走到第 n 块地砖。走到第 i 块地砖需要消耗 a_i 的体力值。每次,小U可以选择向前走一步或者向前走两步,目的是消耗最少的体力值走到第 n 块地砖。
请你帮忙计算小U走到第 n 块地砖时消耗的最小体力值。
2. 测试样例
样例1:
输入:
n = 5, a = [0, 3, 2, 1, 0]
输出:2
样例2:
输入:
n = 4, a = [0, 5, 6, 0]
输出:5
样例3:
输入:
n = 6, a = [0, 1, 2, 3, 1, 0]
输出:3
3. 解题思路
一道DP类问题,需要找到最小消耗值,跟走楼梯问题相似,小U只能前进一步或者两步,因此当前的消耗值只有两种情况:
- 从第
i-1块砖前进一步到第i块转; - 从第
i-2块砖前进一步到第i块转;
由此可得动态转移方程为:
dp(i) = min{a(i)+dp(i-1), a(i)+dp(i-2)}
关键步骤:
-
处理边界情况:
- 如果
n为 1,直接返回a[0]。 - 如果
n为 2,返回Math.min(a[0], a[1])。
- 如果
-
初始化
dp数组:dp[0] = a[0]和dp[1] = a[1]。
-
动态规划状态转移:
dp[i] = Math.min(a[i] + dp[i - 1], a[i] + dp[i - 2]);。
-
返回结果:
return dp[n - 1];
4. 代码
public class Main {
public static int solution(int n, int[] a) {
int[] dp = new int[n];
// 判断一下边界
dp[0] = 0;
if(n > 1) dp[1] = a[1];
for(int i=2; i<n; i++){
// 动态转移方程
dp[i] = Math.min(a[i] + dp[i-1], a[i] + dp[i-2]);
}
// 返回结果
return dp[n-1];
}
public static void main(String[] args) {
System.out.println(solution(15, new int[]{8,6,10,13,2,6,8,11,15,8,10,4,11,16,6}) == 58);
System.out.println(solution(4, new int[]{0, 5, 6, 0}) == 5);
System.out.println(solution(6, new int[]{0, 1, 2, 3, 1, 0}) == 3);
}
}
其中,dp(i)表示从起点到第i块地砖所需要的最小消耗值。
首先判断一下n是否大于1,如果大于1,那么dp[1] = a[1],否则直接返回0,之后从i = 2开始,进行动态转移,计算每个dp(i)的值,最后返回dp[n-1]。