面试之算法基础系列(1)最长子字符串、字符串同构

简介: 代码如下

1.最长子字符串

题目为:

【题目】

给定一个字符串,给定一个数字k ( 0< k ≤ 字符串长度),输出最长的包含k个不同字符子串的长度。

【Example】

“cbca”, k=2,输出最长的包含2个不同字符子串的长度。

答案:3

最容易想到的是暴力解法,就是遍历求出字符串的所有子串,并找出不同字符为k的最长字符,Python代码如下:

def find_max_substring(string, k):
    str_length = len(string)
    sub_string_list = (string[i:i + j + 1] for j in range(str_length) for i in range(str_length - j))
    length_list = []
    for sub_string in sub_string_list:
        if len(set(list(sub_string))) == k:
            length_list.append(len(sub_string))
    return max(length_list)
if __name__ == '__main__':
    string = input()
    k = int(input())
    max_length = find_max_substring(string, k)
    print(max_length)

显然,这种实现方式效率是很低的,虽然使用了生成器,但是在性能方面还是有很大的问题,同时未考虑特殊情况。

后来查询了一些资料,使用了同向双指针和字典来对实现方式进行了优化:

def find_max_substring(string, k):
    str_length = len(string)
    if str_length == 0 or k == 0:
        return 0
    count = 0
    left = 0
    right = 0
    res = 0
    count_dic = {}
    while right < str_length:
        if string[right] not in count_dic or count_dic[string[right]] == 0:
            count += 1
            count_dic[string[right]] = 1
        else:
            count_dic[string[right]] += 1
        right += 1
        while count > k:
            count_dic[string[left]] -= 1
            if count_dic[string[left]] == 0:
                count -= 1
            left += 1
        res = max(res, right - left)
    return res
if __name__ == '__main__':
    string = input()
    k = int(input())
    max_length = find_max_substring(string, k)
    print(max_length)

在字符串长度为0或者k为0时直接返回0;

通过使用同向双指针的方式,可以做到只遍历一次字符串就能得到答案,从而使时间复杂度为O(n),在字符串上移动滑动窗口的两个指针,来保证窗口内的字符不超过k个,具体如下:

  • 设置指针left、right初始位置均为0,初始化计数数组;
  • 当right小于字符串长度时,每次判断字符s[right]是否位于计数数组中,不在则计数count加1,同时对字典进行更新,并使right指针向右移动;
  • 在字符数超过k时,需要移去窗口中最左侧的字符string[left],同时向右移动left指针使得滑动窗口只包含k个不同字符;
  • 更新最大长度res = max(res, right - left)

此时运行结果如下:

2345_image_file_copy_70.jpg

可以看到,运行效率还是相对较快的。

可以在https://www.lintcode.com/problem/longest-substring-with-at-most-k-distinct-characters/description使用IDE进行运行测试和性能评估。

2.字符串同构

题目为:

【题目】

给定两个字符串s和t,确定它们是否同构。

如果可以替换s中的字符得到t,那么两个字符串是同构的。

在保持字符顺序的同时,必须用另一个字符替换出现的所有字符。两个字符不能映射到同一个字符,但一个字符可以映射到自身。

【Example】

Input: s = “egg”, t = “add”

Output: true

Input: s = “foo”, t = “bar”

Output: false

Input: s = “paper”, t = “title”

Output: true

可以看到,实际上就是判断字符串是否结构相同,可以按照如下思路实现:

两个字符串对应位置上的字母要具有一一对应的关系,如果s[i]为a、t[i]=b,则a对应的就是b,如果后面s[j]为a,则t[j]也必须为b,若t[j]为其他字母,则判定为非同构。

要实现这种一一对应关系,可以使用字典,具体如下:

如果两个字符串长度不同,直接返回False;

如果字典中没有相应成对字母,就在字典中加入字母对;

如果键已经存在,判断一下t中对应的字母是否和字典中对应的值相同,不相同则肯定是非同形态,相同则继续循环;

如果s中不同的字母,对应了t中相同的值,即不同的键对应的值相同,例如s='mn'、t=‘mm’,这是属于非同构的,可以通过判断键、值的唯一值个数来判断是否属于这种情况。

Python代码实现如下:

def is_isomorphic(s, t):
    s_len = len(s)
    if s_len != len(t):
        return False
    char_pair = {}
    for i in range(s_len):
        if s[i] not in char_pair:
            char_pair[s[i]] = t[i]
        elif char_pair[s[i]] != t[i]:
            return False
    return len(char_pair) == len(set(char_pair.values()))
if __name__ == '__main__':
    s = 'egg'
    t = 'add'
    res = is_isomorphic(s, t)
    print(res)

示例输出:

True

LeetCode测试结果如下:

2345_image_file_copy_71.jpg

相关文章
|
1月前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
1月前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
32 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
25天前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
30天前
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩在读者群中分享了关于分库分表的基因算法设计,旨在帮助大家应对一线互联网企业的面试题。文章详细介绍了分库分表的背景、分片键的设计目标和建议,以及基因法的具体应用和优缺点。通过系统化的梳理,帮助读者提升架构、设计和开发水平,顺利通过面试。
美团面试:百亿级分片,如何设计基因算法?
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
67 2
|
2月前
|
机器学习/深度学习 JavaScript 算法
面试中的网红虚拟DOM,你知多少呢?深入解读diff算法
该文章深入探讨了虚拟DOM的概念及其diff算法,解释了虚拟DOM如何最小化实际DOM的更新,以此提升web应用的性能,并详细分析了diff算法的实现机制。
|
3月前
|
消息中间件 存储 算法
这些年背过的面试题——实战算法篇
本文是技术人面试系列实战算法篇,面试中关于实战算法都需要了解哪些内容?一文带你详细了解,欢迎收藏!
|
3月前
|
安全 Java 编译器
【Java基础面试二十九】、说一说你对字符串拼接的理解
这篇文章讨论了Java中字符串拼接的四种常用方式(使用`+`运算符、`StringBuilder`、`StringBuffer`和`String`类的`concat`方法),每种方式适用的场景,以及在不同情况下的性能考量。
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
8天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?