AI刷题(二) | 豆包MarsCode AI刷题

134 阅读4分钟

双指针


最小替换子串长度

问题描述

小F得到了一个特殊的字符串,这个字符串只包含字符ASDF,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得ASDF这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。

测试样例

样例1:

输入:input = "ADDF"
输出:1

样例2:

输入:input = "ASAFASAFADDD"
输出:3

样例3:

输入:input = "SSDDFFFFAAAS"
输出:1

样例4:

输入:input = "AAAASSSSDDDDFFFF"
输出:0

样例5:

输入:input = "AAAADDDDAAAASSSS"
输出:4

解题思路

我们需要在字符串中找到一个最小的子串,使得替换掉该子串的字符后,整个字符串中 ASDF 的出现次数能够相等。由于字符串长度是 4 的倍数,我们可以计算出每个字符的理想出现次数,即 len(input) / 4。然后,我们使用滑动窗口来寻找最小的子串,满足替换该子串后各字符频次达到理想值。

算法步骤

  1. 初始化理想频次
    计算每个字符的理想频次 ideal_count = len(input) // 4
  2. 统计当前字符频次
    使用 Counter 统计字符串中 ASDF 各字符的频次,得到 current_counts
  3. 计算需要调整的频次
    计算每个字符的超出理想频次的数量,即需要被替换的字符数,它表示在子串中至少需要包含多少个字符来进行替换,使整个字符串达到理想状态。 如果所有字符的值都为 0,说明字符串已经满足要求,直接返回 0
  4. 滑动窗口查找最小子串
    • 定义左右指针 leftright 以及 window_counts,用于记录当前窗口中各字符的频次。
    • 从左到右扩展右指针 right,每加入一个字符,更新 window_counts
    • 在窗口包含所需的替换字符数量时,开始收缩左指针 left,直到窗口不再满足条件。
    • 在每次满足条件时,记录当前窗口的长度,并更新 min_length 保存最小的子串长度。
  5. 返回结果

代码

def solution(input):
    # Please write your code here
    ideal_count = len(input) // 4
    
    # 统计当前频次
    current_counts = {char: input.count(char) for char in 'ASDF'}
    
    # 计算需要替换的字符数
    needed_replacements = {char: max(0, current_counts[char] - ideal_count) for char in 'ASDF'}
    
    # 如果不需要替换,直接返回0
    if all(needed_replacements[char] == 0 for char in 'ASDF'):
        return 0
    
    # 滑动窗口初始化
    left = 0
    min_length = len(input)
    window_counts = {char: 0 for char in 'ASDF'}
    
    # 滑动窗口算法
    for right in range(len(input)):
        # 更新窗口内字符计数
        window_counts[input[right]] += 1
        
        # 检查窗口是否满足替换条件
        while all(window_counts[char] >= needed_replacements[char] for char in 'ASDF'):
            # 更新最小长度
            min_length = min(min_length, right - left + 1)
            
            # 移动左指针
            window_counts[input[left]] -= 1
            left += 1
    
    return min_length

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution("ADDF") == 1 )
    print(solution("ASAFASAFADDD") == 3)

字典序最小的01字符串

问题描述

小U拥有一个由0和1组成的字符串,她可以进行最多k次操作,每次操作可以交换相邻的两个字符。目标是通过这些操作,使得最终得到的字符串字典序最小。

例如,小U当前有一个字符串 01010,她最多可以进行 2 次相邻字符交换操作。通过这些操作,她可以将字符串调整为 00101,这是可以通过不超过2次操作得到的字典序最小的字符串。

现在,小U想知道,经过最多k次操作后,能够得到的字典序最小的字符串是什么。


测试样例

样例1:

输入:n = 5, k = 2, s = "01010"
输出:'00101'

样例2:

输入:n = 7, k = 3, s = "1101001"
输出:'0110101'

样例3:

输入:n = 4, k = 1, s = "1001"
输出:'0101'

解题思路

解决该题目,我们可以使用贪心算法的思想。 目标是使字符串的字典序最小,因此每次操作时优先将字符 '0' 移动到最前面,尽可能地将字符 '1' 往后移即可

算法步骤

  • 遍历字符串:找到每个 '0' 并设法将它往前移动。
  • 相邻交换:每次交换会消耗一次操作次数 k,直到操作次数耗尽。
  • 贪心移动:每次总是尽可能将 '0' 往前移,以便字典序更小。

代码

def solution(n: int, k: int, s: str) -> str:
    # write code here
    s = list(s)  # 将字符串转换为列表以便进行交换操作
    for i in range(n):
        if s[i] == '0':
            continue  # 当前位置已经是0,不需要交换
        # 找到当前位置之后最近的0
        for j in range(i+1, n):
            if s[j] == '0':
                # 计算从j到i的交换次数
                swaps = j - i
                if swaps <= k:
                    # 进行交换
                    s[i], s[j] = s[j], s[i]
                    k -= swaps
                    break
    return ''.join(s)

if __name__ == '__main__':
    print(solution(5, 2, "01010") == '00101')
    print(solution(7, 3, "1101001") == '0110101')
    print(solution(4, 1, "1001") == '0101')