刷题笔记:178 最大胜利次数问题 | 豆包MarsCode AI刷题

65 阅读3分钟

今天分享一道我个人认为非常有意思的题目与思路分析:是题库中的“连续自然数乘积问题”。 首先,展示题目如下:

问题描述

小S在学习素数因子的分解,并希望在 [1, n] 的范围内找到一些连续的自然数,这些数的乘积最多包含 k 个不同的素因子。任务是找到可以取的连续自然数的最大长度。

解题思路

  1. 素因子分解:首先,需要对每个数进行素因子分解,以确定其素因子。
  2. 滑动窗口:使用滑动窗口技术来遍历 [1, n] 范围内的所有连续自然数序列。
  3. 维护素因子集合:在滑动窗口中维护一个集合来记录当前窗口内所有数的素因子。
  4. 调整窗口大小:当集合中的素因子数量超过 k 时,调整窗口的起始位置,直到满足条件。
  5. 记录最大长度:在遍历过程中记录满足条件的最大窗口长度。

实现代码

以下是实现这一思路的代码:

import java.util.*;
public class Main {
    public static int solution(int n, int k) {
        Map<Integer, Integer> primeCount = new HashMap<>();
        int left = 1, right = 1, maxLen = 0;
        while (right <= n) {
            // 获取当前右边界数的素因子
            for (int prime : primeFactors(right)) {
                primeCount.put(prime, primeCount.getOrDefault(prime, 0) + 1);
            }
            // 如果素因子的种类超过k,则收缩左边界
            while (primeCount.size() > k) {
                for (int prime : primeFactors(left)) {
                    int count = primeCount.get(prime);
                    if (count == 1) {
                        primeCount.remove(prime);
                    } else {
                        primeCount.put(prime, count - 1);
                    }
                }
                left++;
            }
            // 更新最大长度
            maxLen = Math.max(maxLen, right - left + 1);
            right++;
        }
        return maxLen;
    }
    
    private static Set<Integer> primeFactors(int number) {
        Set<Integer> factors = new HashSet<>();
        for (int i = 2; i <= number / i; i++) {
            while (number % i == 0) {
                factors.add(i);
                number /= i;
            }
        }
        if (number > 1) {
            factors.add(number);
        }
        return factors;
    }
    
    public static void main(String[] args) {
        System.out.println(solution(10, 3) == 6);
        System.out.println(solution(20, 5) == 12);
        System.out.println(solution(100, 4) == 10);
    }
}
解题思路
  1. 初始化:创建一个哈希表 primeCount 来记录每个素因子的出现次数,以及两个指针 leftright 来表示滑动窗口的左右边界。
  2. 滑动窗口:通过右指针 right 遍历从 1 到 n 的每个数。
  3. 素因子分解:对每个数调用 primeFactors 方法,获取其素因子,并在 primeCount 中更新这些素因子的计数。
  4. 调整窗口大小:如果窗口内素因子的种类超过 k,则通过左指针 left 缩小窗口,直到素因子的种类不超过 k。
  5. 更新最大长度:在每次调整窗口后,计算当前窗口的长度,并与 maxLen 进行比较,更新最大长度。
时间复杂度
  • 素因子分解的时间复杂度为 O(sqrt(n))。
  • 滑动窗口的时间复杂度为 O(n)。
  • 总的时间复杂度约为 O(n * sqrt(n))。
空间复杂度
  • 使用了哈希表来存储素因子及其计数,最坏情况下空间复杂度为 O(k)。

学习心得

通过分析这段代码,我学到了以下几方面的知识:

  1. 滑动窗口技术:这是一种处理数组或序列问题的有效方法,通过两个指针来维护一个窗口,并根据条件调整窗口大小。
  2. 素因子分解:素数理论在算法中的应用,如何高效地分解一个数的素因子。
  3. 哈希表的使用:通过哈希表来记录和更新素因子的出现次数,提高了代码的效率。
  4. 算法设计:如何将一个复杂的数学问题转化为可编程的算法,并通过代码实现。 这个问题的解决过程不仅加深了我对算法和数据结构的理解,也锻炼了我在实际问题中应用这些知识的能力。在未来的学习和工作中,我将尝试将这种思路和方法应用到更多的问题解决中。