LeetCode2606. 找到最大开销的子字符串
给你一个字符串 s ,一个字符 互不相同 的字符串 chars 和一个长度与 chars 相同的整数数组 vals 。
子字符串的开销 是一个子字符串中所有字符对应价值之和。空字符串的开销是 0 。
字符的价值 定义如下:
-
如果字符不在字符串
chars中,那么它的价值是它在字母表中的位置(下标从 1 开始)。- 比方说,
'a'的价值为1,'b'的价值为2,以此类推,'z'的价值为26。
- 比方说,
-
否则,如果这个字符在
chars中的位置为i,那么它的价值就是vals[i]。
请你返回字符串 s 的所有子字符串中的最大开销。
示例 1:
输入: s = "adaa", chars = "d", vals = [-1000]
输出: 2
解释: 字符 "a" 和 "d" 的价值分别为 1 和 -1000 。
最大开销子字符串是 "aa" ,它的开销为 1 + 1 = 2 。
2 是最大开销。
示例 2:
输入: s = "abc", chars = "abc", vals = [-1,-1,-1]
输出: 0
解释: 字符 "a" ,"b" 和 "c" 的价值分别为 -1 ,-1 和 -1 。
最大开销子字符串是 "" ,它的开销为 0 。
0 是最大开销。
提示:
s只包含小写英文字母。chars只包含小写英文字母,且 互不相同 。
思路分析
根据字符串 chars 和数组 vals 可以得到所有小写英语字母对应的价值,将字符串 s 中的每个字符转换成对应的价值,得到价值数组。计算字符串 s 的所有子字符串的最大开销,等价于计算价值数组的最大子字符串和。
用 n 表示字符串 s 的长度。为了得到字符串 s 的所有子字符串的最大开销,对于每个 0≤i<n需要分别计算以下标 i 结尾的所有子字符串的最大开销,然后在这 n 个最大开销的子字符串中寻找所有子字符串的最大开销。
由于当 i>0 时,以下标 i 结尾的子字符串的最大开销可以通过以下标 i−1 结尾的子字符串的最大开销计算得到,因此可以使用动态规划计算以每个下标结尾的子字符串的最大开销。
创建长度为 n 的数组 dp,其中 dp[i]] 为以下标 i 结尾的子字符串的最大开销,子字符串可以为空。以下用 val[c] 表示字符 c 的价值。
当 i=0 时,以下标 i 结尾的非空子字符串只有一个,开销为 val[s[0]],空字符串的开销为 000,因此动态规划的边界情况是 dp[0]=max(val[s[0]],0)。
当 i>0 时,dp[i−1] 已知,以下标 i 结尾的子字符串的开销有以下三种情况。
如果当前子字符串不为空且包含下标 i−1,则由于以下标 i−1 结尾的子字符串的最大开销是 dp[i−1],因此当包含下标 i−1 时,当前子字符串的最大开销是 dp[i−1]+val[s[i]]。
如果当前子字符串不为空且不包含下标 i−11,则当前子字符串只有一个元素,当前子字符串的开销为 val[s[i]]。
如果当前子字符串为空,则当前子字符串的开销为 0。
算法代码
public int maximumCostSubstring(String s, String chars, int[] vals) {
Map < Character, Integer > valsMap = new HashMap < Character, Integer > ();
int m = chars.length();
for (int i = 0; i < m; i++) {
valsMap.put(chars.charAt(i), vals[i]);
}
for (char c = 'a'; c <= 'z'; c++) {
if (!valsMap.containsKey(c)) {
valsMap.put(c, c - 'a' + 1);
}
}
int n = s.length();
int[] dp = new int[n];
dp[0] = Math.max(valsMap.get(s.charAt(0)), 0);
int maxCost = dp[0];
for (int i = 1; i < n; i++) {
dp[i] = Math.max(Math.max(dp[i - 1], 0) + valsMap.get(s.charAt(i)), 0);
maxCost = Math.max(maxCost, dp[i]);
}
return maxCost;
}
结果详情
算法复杂度
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN)一起进步,一起成长!