构造特定数组的逆序拼接
问题描述
小U得到了一个数字n,他的任务是构造一个特定数组。这个数组的构造规则是:对于每个i从1到n,将数字n到i逆序拼接,直到i等于n为止。最终,输出这个拼接后的数组。
例如,当n等于3时,拼接后的数组是 [3, 2, 1, 3, 2, 3]。
测试样例
样例1:
输入:
n = 3
输出:[3, 2, 1, 3, 2, 3]
样例2:
输入:
n = 4
输出:[4, 3, 2, 1, 4, 3, 2, 4, 3, 4]
样例3:
输入:
n = 5
输出:[5, 4, 3, 2, 1, 5, 4, 3, 2, 5, 4, 3, 5, 4, 5]
1. 题目理解
关键点:
-
输入一个数字n
-
需要构造n个序列
-
第i个序列是从n到i的逆序数字
-
将所有序列依次拼接
示例分析(n=3):
i=1时:[3,2,1]
i=2时:[3,2]
i=3时:[3]
最终结果:[3,2,1,3,2,3]
2.代码
public static int[] constructArray(int n) {
// 1. 计算结果数组长度
int len = 0;
for (int i = 1; i <= n; i++) {
len += (n - i + 1);
}
// 2. 构造结果数组
int[] result = new int[len];
int index = 0;
// 3. 填充数组
for (int i = 1; i <= n; i++) {
for (int j = n; j >= i; j--) {
result[index++] = j;
}
}
return result;
}
}
3. 算法步骤详解
步骤1:计算长度
-
第1个序列长度:n
-
第2个序列长度:n-1
-
第3个序列长度:n-2
...以此类推
- 总长度 = n + (n-1) + (n-2) + ... + 1
步骤2:构造数组
-
外层循环i从1到n
-
内层循环j从n到i(逆序)
-
依次填充数字
步骤3:示例执行过程(n=3)
i=1: j=3,2,1 -> [3,2,1] i=2: j=3,2 -> [3,2,1,3,2] i=3: j=3 -> [3,2,1,3,2,3]
4. 复杂度分析
时间复杂度:O(n²)
-
外层循环:n次
-
内层循环:最多n次
-
总操作次数:n + (n-1) + ... + 1 = n(n+1)/2
空间复杂度:O(n²)
- 结果数组长度:n(n+1)/2
数组元素之和最小化
问题描述
小c希望构建一个包含n个元素的数组,且满以下条件: 1.数组中所有的元素两两不同 2.数组所有元素的最大公约数为k 3.数组元素之和尽可能小 任务是输出数组元素之和的最小值
测试样例
样例1:
输入:
n = 3,k = 1
输出:6
样例2:
输入:
n = 2, k = 2
输出:6
样例3:
输入:
n = 4, k = 3
输出:30
问题理解
你需要构造一个包含 n 个元素的数组,满足以下条件:
- 数组中的所有元素两两不同。
- 数组所有元素的最大公约数为
k。 - 数组元素之和尽可能小。
解题思路
-
最大公约数为
k:- 这意味着数组中的每个元素都必须是
k的倍数。 - 因此,我们可以考虑从
k开始,逐步增加k的倍数来构造数组。
- 这意味着数组中的每个元素都必须是
-
数组元素两两不同:
- 为了避免重复,我们可以从
k开始,每次增加k的倍数,直到找到n个不同的元素。
- 为了避免重复,我们可以从
-
数组元素之和尽可能小:
- 为了使数组元素之和最小,我们应该从最小的
k的倍数开始,逐步增加。
- 为了使数组元素之和最小,我们应该从最小的
算法步骤
-
初始化一个变量
current为k,表示当前考虑的数。 -
初始化一个列表
result来存储数组元素。 -
循环
n次:- 将
current添加到result中。 - 将
current增加k,以确保下一个数是k的倍数且不重复。
- 将
-
计算
result中所有元素的和,并返回该和。
代码
import java.util.List;
public class Main {
public static int solution(int n, int k) {
// 初始化当前数为 k
int current = k;
// 初始化结果列表
List<Integer> result = new ArrayList<>();
// 循环 n 次
for (int i = 0; i < n; i++) {
// 将当前数添加到结果列表
result.add(current);
// 将当前数增加 k
current += k;
}
// 计算结果列表中所有元素的和
int sum = 0;
for (int num : result) {
sum += num;
}
// 返回和
return sum;
}
public static void main(String[] args) {
System.out.println(solution(3, 1) == 6);
System.out.println(solution(2, 2) == 6);
System.out.println(solution(4, 3) == 30);
}
}
最小前缀操作问题
问题描述
小U和小R有两个字符串,分别是 S 和 T,现在小U需要通过对 S 进行若干次操作,使其变成 T 的一个前缀。操作可以是修改 S 的某一个字符,或者删除 S 末尾的字符。现在你需要帮助小U计算出,最少需要多少次操作才能让 S 变成 T 的前缀。
测试样例
样例1:
输入:
S = "aba", T = "abb"输出:1
样例2:
输入:
S = "abcd", T = "efg"输出:4
样例3:
输入:
S = "xyz", T = "xy"输出:1
样例4:
输入:
S = "hello", T = "helloworld"输出:0
样例5:
输入:
S = "same", T = "same"输出:0
-
问题分析:
-
目标是将字符串S转换为T的前缀
-
允许的操作有两种:
-
修改某个字符
-
删除末尾字符
-
特殊情况处理:
-
如果S已经是T的前缀,直接返回0
-
可以使用T.startsWith(S)快速判断
3. 主要情况分类:
-
情况1:S比T长
-
必须删除多余的字符(sLen - tLen次操作)
-
还需要修改不匹配的字符
-
情况2:S长度小于等于T
-
只需要修改不匹配的字符
-
示例分析:
- S和T等长,只需修改最后一个字符
- 操作次数 = 1
例2: S = "abcd", T = "efg"
- S比T长,需要删除1个字符
- 还需要修改3个字符
- 操作次数 = 1 + 3 = 4
例3: S = "xyz", T = "xy"
- S比T长,需要删除1个字符
- 操作次数 = 1
代码
public static int solution(String S, String T) {
// 如果S已经是T的前缀,直接返回0
if (T.startsWith(S)) {
return 0;
}
int sLen = S.length();
int tLen = T.length();
// 如果S比T长,需要删除多余的字符再修改不匹配的字符
if (sLen > tLen) {
int deleteCount = sLen - tLen;
int changeCount = 0;
for (int i = 0; i < tLen; i++) {
if (S.charAt(i) != T.charAt(i)) {
changeCount++;
}
}
return deleteCount + changeCount;
}
// 如果S长度小于等于T,只需要计算需要修改的字符数
int changeCount = 0;
for (int i = 0; i < sLen; i++) {
if (S.charAt(i) != T.charAt(i)) {
changeCount++;
}
}
return changeCount;
}
public static void main(String[] args) {
System.out.println(solution("aba", "abb") == 1);
System.out.println(solution("abcd", "efg") == 4);
System.out.println(solution("xyz", "xy") == 1);
System.out.println(solution("hello", "helloworld") == 0);
System.out.println(solution("same", "same") == 0);
}
}
-
时间复杂度分析:
-
O(min(len(S), len(T)))
-
只需要遍历较短的字符串长度
-
空间复杂度分析:
-
O(1)
-
只使用了常数级别的额外空间
这道题的关键是理解:
-
当S比T长时,必须先考虑删除操作
-
对于需要保留的字符,只需要考虑修改操作
-
不需要实际执行修改操作,只需要计算次数