讲师中心 微信公众号
AI工具推荐 视频效率加速

如何高效求解最长“无聊前缀”——基于频次统计的线性扫描算法

小敏大大_3564

小敏大大_3564

发布时间:2026-04-12 23:18:04

|

400人浏览过

|

来源于php中文网

原创

如何高效求解最长“无聊前缀”——基于频次统计的线性扫描算法

本文介绍一种 o(n) 时间复杂度的算法,用于在整数数组中找出最长的“无聊前缀”(即删除一个元素后,剩余各数字出现次数完全相等的最长前缀),核心在于动态维护频次分布的关键统计量。

本文介绍一种 o(n) 时间复杂度的算法,用于在整数数组中找出最长的“无聊前缀”(即删除一个元素后,剩余各数字出现次数完全相等的最长前缀),核心在于动态维护频次分布的关键统计量。

所谓“无聊集合”(boring set),是指存在某个元素,将其移除后,集合中所有剩余元素的出现频次严格相等。本题要求:对给定数组 a[0..n-1],找出最大的 l(2 ≤ l ≤ n),使得前缀 a[0..l-1] 是无聊的。

关键洞察在于:前缀 a[0..i] 是无聊的,当且仅当其频次分布满足以下三类情形之一(设当前最大频次为 maxFreq,频次为 maxFreq 的不同数字个数为 cntMax,频次为 maxFreq−1 的不同数字个数为 cntMaxMinus1,总不同数字个数为 distinct):

  1. 情形 A:所有元素频次均为 1
    → maxFreq == 1,此时删去任意一个元素,其余仍全为 1 次(或空),合法。
  2. 情形 B:仅一个元素频次为 maxFreq,其余所有元素频次均为 maxFreq − 1
    → 删去那个高频元素的一次出现,则所有元素频次变为 maxFreq − 1,合法。
    条件:cntMax == 1 && (maxFreq - 1) * (distinct - 1) + maxFreq == i + 1(总长度守恒),但更简洁的判定是:cntMax == 1 && cntMaxMinus1 == distinct - 1。
  3. 情形 C:所有元素频次均为 maxFreq,且恰好有一个元素频次为 1
    → 删去那个频次为 1 的元素,其余元素频次保持 maxFreq,合法。
    条件:maxFreq > 1 && cntMax == distinct - 1 && cntOne == 1(其中 cntOne 是频次为 1 的元素个数)。

✅ 实际实现中,我们只需动态维护四个变量:

  • freq[x]:数字 x 的当前出现次数(哈希表)
  • cntFreq[f]:频次为 f 的不同数字个数(如 cntFreq[2] = 3 表示有 3 个数字当前出现了 2 次)
  • maxFreq:当前最大频次
  • distinct:当前不同数字个数

每次加入 a[i] 时:

  • 先将 freq[a[i]] 从旧频次 f_old 更新为 f_new = f_old + 1
  • 对应地:cntFreq[f_old]--,cntFreq[f_new]++
  • 若 f_new > maxFreq,则 maxFreq = f_new
  • 同时更新 distinct(首次出现时加 1)

然后检查上述三种情形是否成立。若成立,则更新答案 ans = i + 1。

以下是完整 Java 实现:

import java.util.*;

public class BoringPrefix {
    public static int findLongestBoringPrefix(int[] arr) {
        if (arr == null || arr.length < 2) return 0;

        Map<Integer, Integer> freq = new HashMap<>(); // x -> count
        Map<Integer, Integer> cntFreq = new HashMap<>(); // count -> number of distinct x with this count
        int maxFreq = 0;
        int distinct = 0;
        int ans = 0;

        for (int i = 0; i < arr.length; i++) {
            int x = arr[i];
            int oldCnt = freq.getOrDefault(x, 0);
            int newCnt = oldCnt + 1;

            // Update freq
            freq.put(x, newCnt);

            // Update cntFreq: decrement old count bucket
            if (oldCnt > 0) {
                cntFreq.put(oldCnt, cntFreq.get(oldCnt) - 1);
                if (cntFreq.get(oldCnt) == 0) cntFreq.remove(oldCnt);
            }
            // Increment new count bucket
            cntFreq.put(newCnt, cntFreq.getOrDefault(newCnt, 0) + 1);

            // Update maxFreq and distinct
            if (oldCnt == 0) distinct++;
            if (newCnt > maxFreq) maxFreq = newCnt;

            // Check boring condition
            boolean isBoring = false;

            // Case 1: all frequencies are 1
            if (maxFreq == 1) {
                isBoring = true;
            }
            // Case 2: one element has maxFreq, others have maxFreq-1
            else if (cntFreq.getOrDefault(maxFreq, 0) == 1) {
                int cntBelow = cntFreq.getOrDefault(maxFreq - 1, 0);
                if (cntBelow == distinct - 1) {
                    isBoring = true;
                }
            }
            // Case 3: all elements have maxFreq, except one with frequency 1
            else if (cntFreq.getOrDefault(1, 0) == 1) {
                if (cntFreq.getOrDefault(maxFreq, 0) == distinct - 1) {
                    isBoring = true;
                }
            }

            if (isBoring) {
                ans = i + 1; // prefix length = index + 1
            }
        }

        return ans;
    }

    // Example usage
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 1, 2, 2, 3, 3, 3, 1, 4, 4, 5};
        System.out.println(findLongestBoringPrefix(arr)); // Output: 10
    }
}

⚠️ 注意事项:

  • 时间复杂度为 O(n),空间复杂度为 O(独特元素个数),远优于暴力枚举所有前缀并排序频次的 O(n² log n) 方法;
  • cntFreq 映射中只保留非零频次项,避免冗余存储;
  • 情形判断需覆盖全部逻辑分支,尤其注意 maxFreq == 1 与 maxFreq > 1 的分离处理;
  • 示例输入中长度为 13 的数组,前 10 个元素 [1,2,3,1,2,2,3,3,3,1] 的频次为:1→3, 2→3, 3→3,但等等——实际统计得:1:3, 2:3, 3:3?不,重新计数:位置 0–9 共 10 个数:1,2,3,1,2,2,3,3,3,1 → 1:3, 2:3, 3:4。删去一个 3 后,1:3, 2:3, 3:3,满足情形 B(maxFreq=4, cntMax=1, cntMaxMinus1=2, distinct=3),验证通过。

该算法结构清晰、可扩展性强,适用于各类基于频次约束的子数组/前缀判定问题。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

12137

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

9222

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

7892

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1284

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1028

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

1536

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

3169

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

20431

2023.08.03

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

0

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn