笔试强训 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);
    }
}
相关推荐
彧azz7 天前
算法设计与分析:贪心与动态规划
数据结构·学习·算法·贪心算法·动态规划
伟大的车尔尼8 天前
贪心题目:优势洗牌
贪心
Logic1018 天前
C语言/数据结构动态规划题解:Kadane算法求最大子数组和——O(n)时间O(1)空间
c语言·数据结构·动态规划·贪心·时间复杂度·算法题·最大子数组和
梦帮科技9 天前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
语戚9 天前
力扣 1621. 大小为K的不重叠线段的数目:动态规划(Java 实现)
java·算法·leetcode·动态规划·力扣·dp
青山木9 天前
Hot 100 --- 最长有效括号
java·数据结构·算法·leetcode·动态规划
这料鬼有毒9 天前
二刷hot100-1143.最长公共子序列
算法·leetcode·动态规划
Tisfy9 天前
LeetCode 1477.找两个和为目标值且不重叠的子数组:滑动窗口 + 记录前值(动态规划)
动态规划·题解·dp·滑动窗口
gjjwh10 天前
【免费】9月和谐版XPlane12 12.4.3-r1免费下载
模拟
ynchyong10 天前
动态规划解题思路:入门篇
动态规划