Day 44
最小差值

解题思路:
- 排序+计算;
- 注意避免溢出,得到最优解直接返回;
代码实现:
java
import java.util.Arrays;
public class Solution {
public int minDifference(int[] a) {
Arrays.sort(a);
// 使用 int 会溢出
long min = Long.MAX_VALUE;
for (int i = 1; i < a.length; i++) {
long diff = (long) a[i] - a[i - 1];
min = Math.min(min, diff);
// 关键优化
if (min == 0) {
return 0;
}
}
return (int) min;
}
}
kotori 和素因子


解题思路:
- 递归 + 记忆化搜索;
- 递归搜索 numspos 的所有质数因子,定住 pos 的质数因子后,递归搜索 numspos+1 的可以选的质数因子;
- 使用 path 记录当前 0, pos 下,numspos 选择的质数因子组合之和,找到最小的 path
代码实现:
java
import java.util.*;
public class Main{
private static int ret = 0x3f3f3f3f;
private static int path = 0;
private static int[] nums;
private static int n;
private static boolean[] used = new boolean[1010];
// 判断是不是质数
private static boolean isPrime(int num){
if(num == 2) return true;
for(int i = 2; i <= Math.sqrt(num); i++){
if(num % i == 0) return false;
}
return true;
}
private static void dfs(int pos){
if(pos == n){
ret = Math.min(ret, path);
return;
}
// 对当前 nums[pos] 枚举所有质数因子, 然后以此去枚举 nums[pos+1] 被约束下的组合 path
for(int i = 2; i <= nums[pos]; i++){
// 当前 i 是 nums[pos] 的因子,并且该因子未被使用,同时该因子是质数
if(nums[pos] % i != 0 || used[i] || !isPrime(i)){
continue;
}
used[i] = true;
path += i;
dfs(pos + 1);
used[i] = false;
path -= i;
}
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
nums = new int[n];
for(int i = 0; i < n; i++) nums[i] = in.nextInt();
dfs(0);
System.out.println(ret == 0x3f3f3f3f ? -1 : ret);
}
}
dd 爱科学 1.0

解法一:优化状态表示
解题思路:
- 最长递增子序列 + 状态表示优化;
- 状态表示优化:dpi 从以 i 下标对应字符为结尾的最长递增子序列,优化到
dp[c]表示当前处理范围内,以字符c结尾的最长非递减子序列长度。
代码实现:
java
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
char[] s = in.next().toCharArray();
// 关键: dp[1] 表示以 B 为结尾的最长非递减子序列
int[] dp = new int[26];
int max = 0;
for(int i = 1; i <= n; i++){
int cur = s[i-1] - 'A';
// 先找出所有合法前驱中的最大长度,再加上当前字符
int best = 0;
for(int j = 0; j <= cur; j++){
best = Math.max(best, dp[j]);
}
dp[cur] = best + 1;
// 找到所有 dp 元素的最大值
max = Math.max(max, dp[cur]);
}
System.out.println(n - max);
}
}
解法二:贪心 + 二分
解题思路:
dp[k]表示长度为k的非递减子序列中,最小的末尾字符。- 从左到右遍历每个字符
ch。 - 如果
ch >= dp[ret],说明可以直接接到末尾,长度加一。 - 否则二分查找第一个
> ch的位置,用ch替换它。 - 由于允许相同字符,查找的是第一个严格大于
ch的位置。 ret就是最长非递减子序列长度,答案为n - ret。
时间复杂度为 O(n log n),空间复杂度为 O(n)。
代码实现:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
char[] s = in.next().toCharArray();
// dp[i] 表示长度为 i 的非递减子序列中,最小的末尾字符
char[] dp = new char[n + 1];
int ret = 0;
for (int i = 0; i < n; i++) {
char ch = s[i];
// 可以直接接到当前最长序列后面
if (ret == 0 || ch >= dp[ret]) {
dp[++ret] = ch;
} else {
// 查找第一个大于 ch 的位置
int left = 1;
int right = ret;
while (left < right) {
int mid = (left + right) / 2;
if (dp[mid] > ch) {
right = mid;
} else {
left = mid + 1;
}
}
dp[left] = ch;
}
}
System.out.println(n - ret);
}
}