【力扣】2645. 构造有效字符串的最小插入数(动态规划 贪心 滚动数组优化 C++ Go)

简介: 【2月更文挑战第17天】2645. 构造有效字符串的最小插入数(动态规划 贪心 滚动数组优化 C++ Go)

题目链接

题意

给你一个字符串 word ,你可以向其中任何位置插入 "a"、"b" 或 "c" 任意次,返回使 word 有效 需要插入的最少字母数。
如果字符串可以由 "abc" 串联多次得到,则认为该字符串 有效 。
提示:
$1 <= word.length <= 50$
$word$ 仅由字母 "a"、"b" 和 "c" 组成。

思路

dp[i]表示前i个字符构成有效字符串的最小插入数,下标从1开始

  • 初始化为dp[0]=0表示前0个字符构成有效字符串最小需要插入0个字符
  • 最终答案为dp[len(word)]
  • 转移过程:
    • i个字符单独属于一个abc里,需要插入的字符数就是2,转移方程为dp[i]=dp[i-1]+2
    • 如果第i个字符可以跟第i-1个字符属于一个abc,也就是满足word[i]>word[i-1],需要插入的字符数就是-1,即前面可以少插入一个字符,转移方程为dp[i] = min(dp[i], dp[i-1]-1)
  • 贪心的考虑,每个字符都优先跟前面的字符去组合,而且dp[i-1]+2<dp[i-1]-1,所以第二个转移方程可以写为dp[i]=dp[i-1]-1
  • 上述做法的时间复杂度为$O(n)$,空间复杂度也是$O(n)$。
  • 观察代码发现其实状态转移的时候只依赖上一个状态,所以可以使用滚动数组进行优化,优化后的空间复杂度为$O(1)$

    代码

    普通版本golang代码

    func addMinimum(word string) int {
         
      //dp[i]表示前i个字符构成有效字符串的最小插入数
      dp := make([]int, len(word)+2)
      for i := 1; i <= len(word); i++ {
         
          dp[i] = dp[i-1] + 2
          if i > 1 && word[i-1] > word[i-2] {
         
              dp[i] = dp[i-1] - 1
              //dp[i] = min(dp[i], dp[i-1]-1)
          }
      }
      return dp[len(word)]
    }
    

    普通版本c++代码

class Solution {
   
public:
    int addMinimum(string word) {
   
        int n = word.size();
        int dp[n+1];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
   
            dp[i] = dp[i-1]+2;
            if(i>1&&word[i-1]>word[i-2]){
   
                dp[i] = dp[i-1]-1;
            }
        }
        return dp[n];
    }
};

滚动数组版本golang代码

func addMinimum(word string) int {
   
    ans, las := 0, 0
    for i := 1; i <= len(word); i++ {
   
        ans = las + 2
        if i > 1 && word[i-1] > word[i-2] {
   
            ans = las - 1
        }
        las = ans
    }
    return ans
}

滚动数组版本c++代码

class Solution {
   
    public:
        int addMinimum(string word) {
   
            int ans=0;
            int las= 0;
            for (int i = 1; i <= word.size(); i++) {
   
                ans = las + 2;
                if (i > 1 && word[i-1] > word[i-2]) {
   
                    ans = las - 1;
                }
                las = ans;
            }
            return ans;
        }
};
目录
相关文章
|
5月前
|
人工智能 自然语言处理 算法
Go语言统计字符串中每个字符出现的次数 — 简易频率分析器
本案例实现一个字符统计程序,支持中文、英文及数字,可统计用户输入文本中各字符的出现次数,并以整洁格式输出。内容涵盖应用场景、知识点讲解、代码实现与拓展练习,适合学习文本分析及Go语言基础编程。
|
5月前
|
监控 Java 编译器
限流、控并发、减GC!一文搞懂Go项目资源优化的正确姿势
本章介绍Go语言项目在构建与部署阶段的性能调优和资源控制策略,涵盖编译优化、程序性能提升、并发与系统资源管理、容器化部署及自动化测试等内容,助力开发者打造高效稳定的生产级应用。
|
5月前
|
存储 安全 算法
Go语言泛型-泛型对代码结构的优化
Go语言自1.18版本引入泛型,极大提升了代码的通用性与可维护性。通过泛型,开发者可以减少重复代码、提高类型安全性,并增强程序的复用性和可读性。本文详细介绍了泛型在数据结构、算法及映射功能中的应用,展示了其在优化代码结构方面的优势。同时,Go编译器对泛型代码进行类型推导,确保运行时性能不受影响。合理使用泛型,有助于构建更加灵活高效的程序。
|
7月前
|
机器学习/深度学习 存储 监控
上网管理监控软件的 Go 语言流量特征识别算法实现与优化
本文探讨基于Go语言的流量特征识别算法,用于上网管理监控软件。核心内容涵盖AC自动机算法原理、实现及优化,通过路径压缩、哈希表存储和节点合并策略提升性能。实验表明,优化后算法内存占用降低30%,匹配速度提升20%。在1000Mbps流量下,CPU利用率低于10%,内存占用约50MB,检测准确率达99.8%。未来可进一步优化高速网络处理能力和融合机器学习技术。
219 10
|
6月前
|
Java C++
力扣第一道困难题《3. 无重复字符的最长子串》,c++
首先我们看到这个题是肯定有一种暴力的硬解思路的,那就是将两个vector直接链接起来,然后再排序后,直接返回中间值,这个方法实现起来还是非常容易的,
176 0
|
8月前
|
Go 索引
【LeetCode 热题100】394:字符串解码(详细解析)(Go语言版)
本文详细解析了 LeetCode 热题 394:字符串解码。题目要求对编码字符串如 `k[encoded_string]` 进行解码,其中 `encoded_string` 需重复 `k` 次。文章提供了两种解法:使用栈模拟和递归 DFS,并附有 Go 语言实现代码。栈解法通过数字栈与字符串栈记录状态,适合迭代;递归解法则利用函数调用处理嵌套结构,代码更简洁。两者时间复杂度均为 O(n),但递归需注意栈深度问题。文章还总结了解题注意事项及适用场景,帮助读者更好地掌握字符串嵌套解析技巧。
233 6
|
9月前
|
存储 机器学习/深度学习 缓存
🚀 力扣热题 394:字符串解码(详细解析)(Go语言版)
文章提供了两种解法:栈结构和递归解法。栈解法通过维护数字栈与字符串栈,依次处理 `[` 和 `]`,构造解码结果;递归解法则利用函数调用逐层解析嵌套结构。两者时间复杂度均为 $O(n)$,空间复杂度也为 $O(n)$。栈解法直观易懂,适合初学者;递归解法优雅简洁,适合处理深度嵌套规则。掌握这两种方法,可灵活应对类似问题,提升解题能力。
328 11
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数
|
Go 索引
golang 字符串操作实例
package main import s "strings" import "fmt" var p = fmt.Println func main() { p("Contains: ", s.
1002 0