Java C++ 算法leetcode828统计子串中唯一字符乘法原理

Java C++ 算法leetcode828统计子串中唯一字符乘法原理

题目描述

给定一个字符串,你需要统计其中唯一字符的个数。

具体地,你需要统计所有的出现恰好一次的字符的个数。

示例

输入: "ABCDEF"
输出: 6
解释: 
出现一次的字符有 'A', 'B', 'C', 'D', 'E', 'F',因此唯一字符的个数为 6。

输入: "ABCDEFABCDEF"
输出: 0
解释: 
都出现了两次的字符,因此没有唯一字符。

解题思路

这道题可以看成是对于任意子串求解唯一字符的个数,这个问题可以被下面的定理所解决:

对于任意的 $i\le j$,$\text{count(i,j)} = \text{count(1,j)} - \text{count(1,i-1)}$,其中 $\text{count(i,j)}$ 表示区间 $[i,j]$ 中唯一字符的个数。

证明如下:

  • 显然,当 $i=j$ 时,$\text{count(i,j)}=1$,因为这是一个单个字符。
  • 当 $i<j$ 时,我们需要考虑将何时出现重复字符:

    • 假设 $\text{count(1,j)} - \text{count(1,i-1)}=k$,表示区间 $[i,j]$ 中唯一字符的个数为 $k$,则代表区间 $[i,j]$ 中有 $j-i+1-k$ 个字符出现至少两次。
    • 我们接下来考虑新加入一个字符 $c$,并判断这个字符是否会让唯一字符的个数改变:

      • 如果 $c$ 之前在区间 $[i,j]$ 中尚未出现过,由于它是唯一字符,所以唯一字符个数加一。
      • 如果 $c$ 之前在区间 $[i,j]$ 中已经出现过了,那么此时该字符和之前的某个字符 $\hat{c}$ 都存在了,所以唯一字符个数就少了一个。
    • 因此,当我们加入新的 $c$ 时,唯一字符个数的变化可以通过判断 $c$ 是否在区间 $[i,j]$ 中出现来进行决策:

      • 如果 $c$ 在区间内未出现,那么唯一字符个数加一;
      • 如果 $c$ 在区间内已经出现,那么唯一字符个数减一。
    • 由此可以得到结论:区间 $[i+1,j]$ 中唯一字符个数是区间 $[i,j]$ 的唯一字符个数加零或减一。

因此,我们可以用滑动窗口来维护区间的唯一字符个数,每次增加一位字符,就按照定理来决定是否增加或减少唯一字符的个数即可。

代码示例

Java:

public int uniqueLetterString(String S) {
    if(S == null || S.length() == 0) {
        return 0;
    }
    int n = S.length();
    int[] lastIndex = new int[26];
    int[] contribution = new int[26];
    Arrays.fill(lastIndex, -1);
    long result = 0;
    int mod = 1000000007;
    for(int i = 0; i < n; i++) {
        int index = S.charAt(i) - 'A';
        if(lastIndex[index] == -1) {
            contribution[index] = (i + 1);
        } else {
            contribution[index] = (i - lastIndex[index]);
        }
        lastIndex[index] = i;
        result = (result + contribution[index]) % mod;
    }
    return (int)result;
}

C++:

class Solution {
public:
    int uniqueLetterString(string S) {
        if (S.empty()) {
            return 0;
        }
        int n = S.size();
        vector<int> lastIndex(26, -1), contribution(26, 0);
        long long result = 0;
        const int mod = 1e9 + 7;
        for(int i = 0; i < n; i++) {
            int index = S[i] - 'A';
            if(lastIndex[index] == -1) {
                contribution[index] = (i + 1);
            } else {
                contribution[index] = (i - lastIndex[index]);
            }
            lastIndex[index] = i;
            result = (result + contribution[index]) % mod;
        }
        return result;
    }
};

总结

这题用了一个很巧妙的思想。了解这个变换可以帮助我们快速求解子串的相关问题,这里推荐一下书籍:《算法竞赛进阶指南》。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java C++ 算法leetcode828统计子串中唯一字符乘法原理 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • 深入了解Java I/O 之File类

    深入了解Java I/O 之File类 File类的作用 在Java I/O中,File类被用来表示一个文件或目录的路径名。虽然这个类的名字是File,但它实际上只是一个路径名的抽象表示。File类的实例代表的是一个文件或目录的路径,而不是实际上的文件或目录。 File类的常见操作 File类提供了一组重要的方法来操作文件和目录。下面列出了您可能会经常使用的…

    Java 2023年6月1日
    00
  • Sprint Boot @ConfigurationProperties使用方法详解

    @ConfigurationProperties是Spring Boot中的一个注解,它用于将配置文件中的属性值映射到Java类的属性中。在使用Spring Boot开发应用程序时,@ConfigurationProperties是非常重要的。本文将详细介绍@ConfigurationProperties的作用和使用方法,并提供两个示例说明。 @Config…

    Java 2023年5月5日
    00
  • Spring Boot 日志配置方法(超详细)

    Spring Boot日志配置方法(超详细) Spring Boot是一个非常流行的Java开发框架,它提供了多种日志框架,包括Logback、Log4j2、Java Util Logging等。本文将详细介绍Spring Boot日志配置方法,包括配置文件、注解、代码等。 1. 配置文件 Spring Boot的日志配置文件是application.pro…

    Java 2023年5月14日
    00
  • Java编码算法与哈希算法深入分析使用方法

    Java编码算法与哈希算法深入分析使用方法攻略 什么是编码算法? 编码算法是一种将数据从一种格式或表示方式转换为另一种格式或表示方式的算法。在Java编程中,常见的编码算法有Base64,URL编码以及HTML编码等等。 Base64编码 Base64编码是一种将二进制数据转换为可打印的ASCII字符的编码方式。Base64编码将数据每3个字节一组进行编码,…

    Java 2023年5月19日
    00
  • 浅析Java中JSONObject和JSONArray使用

    浅析Java中JSONObject和JSONArray使用 在Java中,我们经常需要处理JSON数据。其中,JSONObject和JSONArray是Java中最常用的两种处理JSON数据的类。本文将为大家介绍JSONObject和JSONArray的基本使用方法和实例,希望对大家有所帮助。 JSONObject的使用 JSONObject是一个类,它表示…

    Java 2023年5月19日
    00
  • JAVA 对象创建与对象克隆

    JAVA 对象创建与对象克隆 在 Java 中,对象创建与对象克隆是非常重要的知识点。 对象创建 Java 中的对象常见的有以下几种创建方式: 使用 new 关键字 使用 new 关键字创建对象是最常见的一种方式,通过这种方式创建出来的对象是一个新的对象实例,具有独立的地址空间。例子如下: public class Person { private Stri…

    Java 2023年5月26日
    00
  • 三天吃透计算机网络八股文

    网络分层结构 计算机网络体系大致分为三种,OSI七层模型、TCP/IP四层模型和五层模型。一般面试的时候考察比较多的是五层模型。最全面的Java面试网站 五层模型:应用层、传输层、网络层、数据链路层、物理层。 应用层:为应用程序提供交互服务。在互联网中的应用层协议很多,如域名系统DNS、HTTP协议、SMTP协议等。 传输层:负责向两台主机进程之间的通信提供…

    Java 2023年4月17日
    00
  • Java异常学习之自定义异常详解

    Java异常学习之自定义异常详解 自定义异常是什么? 在Java的异常体系中,自定义异常指的是用户自己定义的异常类,继承自Throwable或其子类。自定义异常一般用来处理应用程序特别的异常,例如业务逻辑中的特定条件。 如何定义自定义异常? 定义自定义异常需要遵循以下步骤: 创建一个继承自Exception或其子类的Java类; 添加至少一个构造函数,以便在…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部