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

题目链接

题意

给你一个字符串 word ,你可以向其中任何位置插入 “a”、“b” 或 “c” 任意次,返回使 word 有效 需要插入的最少字母数。
如果字符串可以由 “abc” 串联多次得到,则认为该字符串 有效 。
提示:
1 < = w o r d . l e n g t h < = 50 1 <= word.length <= 50 1<=word.length<=50
w o r d word 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]=dp[i-1]-1
  • 上述做法的时间复杂度为 O ( n ) O(n) O(n),空间复杂度也是 O ( n ) O(n) O(n)
  • 观察代码发现其实状态转移的时候只依赖上一个状态,所以可以使用滚动数组进行优化,优化后的空间复杂度为 O ( 1 ) O(1) 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;
		}
};

你可能感兴趣的:(力扣,leetcode,动态规划,c++)