笔试强训 Day 44:最小差值、kotori 和素因子、dd 爱科学 1.0

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);
    }
}
相关推荐
所以遗憾是什么呢?10 小时前
【题解】Educational Codeforces Round 195 (Rated for Div. 2) ABCDE
c++·动态规划·acm·icpc·ccpc·xcpc·codeforecs
lvwangshu16 小时前
川剧复演 题解
动态规划·题解·技巧·性质题·思维好题
All for pursuit.1 天前
【动态规划-21】312.戳气球
数据结构·c++·算法·leetcode·动态规划
y1su2 天前
Leetcode 动态规划 模板
java·数据结构·算法·leetcode·动态规划
MoRanzhi12032 天前
106.正则问题(分治)
python·算法·正则表达式·蓝桥杯·递归·分治算法·字符串处理
w_zero_one2 天前
动态规划(三)
java·算法·动态规划
Tisfy2 天前
LeetCode 2913.子数组不同元素数目的平方和 I:第一题先常数很大的O(n^2)
算法·leetcode·题解·模拟·暴力
木井巳2 天前
【动态规划】三步问题
java·算法·leetcode·动态规划·推荐算法
浅念-3 天前
动态规划:线性DP——多状态DP与子数组专题笔记
c++·笔记·算法·leetcode·职场和发展·动态规划·力扣
不会就选b3 天前
算法日常・每日刷题--<动态规划>26
算法·动态规划