跳到主要内容

97 篇博文 含有标签「字符串」

查看所有标签

· 阅读需 4 分钟

1、题干

给你两个字符串 a 和 b ,它们长度相同。请你选择一个下标,将两个字符串都在 相同的下标 分割开。由 a 可以得到两个字符串: aprefix 和 asuffix ,满足 a = aprefix + asuffix ,同理,由 b 可以得到两个字符串 bprefix 和 bsuffix ,满足 b = bprefix + bsuffix 。请你判断 aprefix + bsuffix 或者 bprefix + asuffix 能否构成回文串。

当你将一个字符串 s 分割成 sprefix 和 ssuffix 时, ssuffix 或者 sprefix 可以为空。比方说, s = "abc" 那么 "" + "abc" , "a" + "bc" , "ab" + "c" 和 "abc" + "" 都是合法分割。

如果 能构成回文字符串 ,那么请返回 true,否则返回 false 。

注意, x + y 表示连接字符串 x 和 y 。

 

示例 1:

输入:a = "x", b = "y"
输出:true
解释:如果 a 或者 b 是回文串,那么答案一定为 true ,因为你可以如下分割:
aprefix = "", asuffix = "x"
bprefix = "", bsuffix = "y"
那么 aprefix + bsuffix = "" + "y" = "y" 是回文串。

示例 2:

输入:a = "abdef", b = "fecab"
输出:true

示例 3:

输入:a = "ulacfd", b = "jizalu"
输出:true
解释:在下标为 3 处分割:
aprefix = "ula", asuffix = "cfd"
bprefix = "jiz", bsuffix = "alu"
那么 aprefix + bsuffix = "ula" + "alu" = "ulaalu" 是回文串。

 

提示:

  • 1 <= a.length, b.length <= 105
  • a.length == b.length
  • a 和 b 都只包含小写英文字母

2、思路

这是回文判断的升级版,考虑4种情况:

  • 字符串1是回文
  • 字符串2是回文
  • 字符串1前缀+字符串2后缀是回文
  • 字符串2前缀+字符串1后缀是回文

实际上前面两种情况可以忽略


具体实现时,可以将常规的回文判断做成辅助函数并扩展:

  • 使用两个字符串作为入参,不同于常规回文,这里需要同时判断两串字符
  • 考虑双串组合的情况,增加一个入参 i,用于标识双串组合的起始位置
  • 遍历过程中如果遇到前后不匹配的字符,则考虑两种情况:
    • 双串相等,可以判定不是回文
    • 双串不等,则判断从该位置开始,如果其中任意一个字符串仍符合回文特性,则返回 true,反之为 false

3、代码

function checkPalindromeFormation(s1: string, s2: string): boolean {
function isPdr(a: string, b: string, i: number = 0) {
for (; i < a.length / 2 >> 0; i++) {
if (a[i] !== b[a.length - i - 1]) return a === b ? false : isPdr(a, a, i) || isPdr(b, b, i);
}
return true;
}
return isPdr(s1, s2) || isPdr(s2, s1);
};

4、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

5、执行结果

image.png

· 阅读需 4 分钟

1、题干

给你一个长度为 n 下标从 0 开始的字符串 blocks ,blocks[i] 要么是 'W' 要么是 'B' ,表示第 i 块的颜色。字符 'W' 和 'B' 分别表示白色和黑色。

给你一个整数 k ,表示想要 连续 黑色块的数目。

每一次操作中,你可以选择一个白色块将它 涂成 黑色块。

请你返回至少出现 一次 连续 k 个黑色块的 最少 操作次数。

 

示例 1:

输入:blocks = "WBBWWBBWBW", k = 7
输出:3
解释:
一种得到 7 个连续黑色块的方法是把第 0 ,3 和 4 个块涂成黑色。
得到 blocks = "BBBBBBBWBW" 。
可以证明无法用少于 3 次操作得到 7 个连续的黑块。
所以我们返回 3 。

示例 2:

输入:blocks = "WBWBBBW", k = 2
输出:0
解释:
不需要任何操作,因为已经有 2 个连续的黑块。
所以我们返回 0 。

 

提示:

  • n == blocks.length
  • 1 <= n <= 100
  • blocks[i] 要么是 'W' ,要么是 'B'
  • 1 <= k <= n

2、思路1

双层遍历,每次取 k 个色块,对白色块计数,取最少白色块数

3、代码

function minimumRecolors(blocks: string, k: number): number {
let ans = k;
for (let i = 0; i < blocks.length; i++) {
for (let j = i, w = 0; j - i < k && j < blocks.length; j++) {
if (blocks[j] === 'W') w++;
if (j - i + 1 === k) ans = Math.min(w, ans);
}
}
return ans;
};

4、复杂度

  • 时间复杂度:O(nk)O(nk)
  • 空间复杂度:O(1)O(1)

5、执行结果

image.png

6、思路2

滑动窗口求解,窗口固定长度为 k,对窗口内白色块计数,取最少白色块数

7、代码

function minimumRecolors(blocks: string, k: number): number {
let w = 0;
for (let i = 0; i < k; i++) {
if (blocks[i] === 'W') w++;
}

let ans = w;
for (let i = k; i < blocks.length; i++) {
if (blocks[i - k] === 'W') w--;
if (blocks[i] === 'W') w++;
ans = Math.min(w, ans);
}

return ans;
};

也可以这样

function minimumRecolors(blocks: string, k: number): number {
let ans = k, w = 0;
for (let i = 0, j = i; i < blocks.length; i++) {
for (; j < i + k && j < blocks.length; j++) {
if (blocks[j] === 'W') w++;
}
if (j - i === k) ans = Math.min(w, ans);
if (blocks[i] === 'W') w--;
}
return ans;
};

8、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

9、执行结果

image.png

· 阅读需 4 分钟

1、题干

如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。

花括号展开的表达式可以看作一个由 花括号逗号小写英文字母 组成的字符串,定义下面几条语法规则:

  • 如果只给出单一的元素 x,那么表达式表示的字符串就只有 "x"R(x) = {x}
    • 例如,表达式 "a" 表示字符串 "a"
    • 而表达式 "w" 就表示字符串 "w"
  • 当两个或多个表达式并列,以逗号分隔,我们取这些表达式中元素的并集。R({e_1,e_2,...}) = R(e_1) ∪ R(e_2) ∪ ...
    • 例如,表达式 "{a,b,c}" 表示字符串 "a","b","c"
    • 而表达式 "{{a,b},{b,c}}" 也可以表示字符串 "a","b","c"
  • 要是两个或多个表达式相接,中间没有隔开时,我们从这些表达式中各取一个元素依次连接形成字符串。R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}
    • 例如,表达式 "{a,b}{c,d}" 表示字符串 "ac","ad","bc","bd"
  • 表达式之间允许嵌套,单一元素与表达式的连接也是允许的。
    • 例如,表达式 "a{b,c,d}" 表示字符串 "ab","ac","ad"​​​​​​
    • 例如,表达式 "a{b,c}{d,e}f{g,h}" 可以表示字符串 "abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"

给出表示基于给定语法规则的表达式 expression,返回它所表示的所有字符串组成的有序列表。

假如你希望以「集合」的概念了解此题,也可以通过点击 “显示英文描述” 获取详情。

 

示例 1:

输入:expression = "{a,b}{c,{d,e}}"
输出:["ac","ad","ae","bc","bd","be"]

示例 2:

输入:expression = "{{a,z},a{b,c},{ab,z}}"
输出:["a","ab","ac","z"]
解释:输出中 不应 出现重复的组合结果。

 

提示:

  • 1 <= expression.length <= 60
  • expression[i]'{''}'',' 或小写英文字母组成
  • 给出的表达式 expression 用以表示一组基于题目描述中语法构造的字符串

2、思路

本题要处理的子表达式主要包括3类:

  • 单层:{xxx,xxx}
  • 嵌套:{{xxx},{xxx}}
  • 相接:{xxx}{xxx}xxx{xxx}{xxx}xxx

具体代码实现逻辑如下:

  • 扁平化:把最内层的单层表达式提取到上一层(这会逐渐把嵌套和单层表达式都处理掉)
  • 拼接组合:拼接组合最内层相接子表达式
  • 重复这两个步骤直到表达式中没有任何花括号
  • 最后对表达式进行拆分、去重、排序

3、代码

function braceExpansionII(exp: string): string[] {
const reg0 = /\{([a-z,]+)\}/g;
const reg1 = new RegExp(`(?<![a-z}])${reg0.source}(?![a-z{])`, 'g');
const reg2 = new RegExp(`(${reg0.source}){2,}|[a-z]+(${reg0.source})+|(${reg0.source})+[a-z]+`, 'g');

while (1) {
const f1 = reg1.test(exp);
if (f1) exp = exp.replace(reg1, '$1');

const f2 = reg2.test(exp);
if (f2) {
exp = exp.replace(reg2, (m) => {
const reg = new RegExp(`${reg0.source}|[a-z]+`, 'g');

const tokenGroup = (m.match(reg) || []).map(s => s.split(/,|\{|\}/).filter(Boolean));

let ans = tokenGroup[0];
for (let i = 1; i < tokenGroup.length; i++) {
const newAns = [];
for (const h of ans) {
for (const t of tokenGroup[i]) {
newAns.push(h + t);
}
}
ans = newAns;
}

return `{${ans.join(',')}}`
});
}

if (!f1 && !f2) break;
}

return [...new Set(exp.split(','))].sort();
};

4、执行结果

image.png

· 阅读需 3 分钟

1、题干

给你一个字符串 s ,它仅包含字符 'a' 和 'b'​​​​ 。

你可以删除 s 中任意数目的字符,使得 s 平衡 。当不存在下标对 (i,j) 满足 i < j ,且 s[i] = 'b' 的同时 s[j]= 'a' ,此时认为 s平衡 的。

请你返回使 s 平衡 的 最少 删除次数。

 

示例 1:

输入:s = "aababbab"
输出:2
解释:你可以选择以下任意一种方案:
下标从 0 开始,删除第 2 和第 6 个字符("aababbab" -> "aaabbb"),
下标从 0 开始,删除第 3 和第 6 个字符("aababbab" -> "aabbbb")。

示例 2:

输入:s = "bbaaaaabb"
输出:2
解释:唯一的最优解是删除最前面两个字符。

 

提示:

  • 1 <= s.length <= 105
  • s[i] 要么是 'a' 要么是 'b' 。​

本题跟剑指 Offer II 092. 翻转字符的思路一样

2、思路1

循环剔除所有 ba 子串并累加剔除次数

3、代码

function minimumDeletions(s: string): number {
let ans = 0;
while (s.includes('ba')) s = s.replace(/ba/g, () => (ans++, ''));
return ans;
};

4、执行结果

image.png

5、思路2

思路1实际上是消除所有字符 b 后面的字符 a,可以使用常规遍历模拟消除过程。

具体实现时需要遍历字符串 s 两次,先统计字符 a 的个数,再消除字符 a

6、代码

function minimumDeletions(s: string): number {
let ac = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === 'a') ac++;
};

let ans = 0, bc = 0;
for (let i = 0; ac > 0 && i < s.length; i++) {
if (s[i] === 'a') bc > 0 ? bc-- : ac--;
else ans++, bc++, ac--;
}

return ans;
};

7、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

8、执行结果

image.png

· 阅读需 4 分钟

1、题干

给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。

由于两个文件 不能 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用,系统会以 (k) 的形式为新文件夹的文件名添加后缀,其中 k 是能保证文件名唯一的 最小正整数

返回长度为 n 的字符串数组,其中 ans[i] 是创建第 i 个文件夹时系统分配给该文件夹的实际名称。

 

示例 1:

输入:names = ["pes","fifa","gta","pes(2019)"]
输出:["pes","fifa","gta","pes(2019)"]
解释:文件系统将会这样创建文件名:
"pes" --> 之前未分配,仍为 "pes"
"fifa" --> 之前未分配,仍为 "fifa"
"gta" --> 之前未分配,仍为 "gta"
"pes(2019)" --> 之前未分配,仍为 "pes(2019)"

示例 2:

输入:names = ["gta","gta(1)","gta","avalon"]
输出:["gta","gta(1)","gta(2)","avalon"]
解释:文件系统将会这样创建文件名:
"gta" --> 之前未分配,仍为 "gta"
"gta(1)" --> 之前未分配,仍为 "gta(1)"
"gta" --> 文件名被占用,系统为该名称添加后缀 (k),由于 "gta(1)" 也被占用,所以 k = 2 。实际创建的文件名为 "gta(2)" 。
"avalon" --> 之前未分配,仍为 "avalon"

示例 3:

输入:names = ["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece"]
输出:["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece(4)"]
解释:当创建最后一个文件夹时,最小的正有效 k 为 4 ,文件名变为 "onepiece(4)"。

示例 4:

输入:names = ["wano","wano","wano","wano"]
输出:["wano","wano(1)","wano(2)","wano(3)"]
解释:每次创建文件夹 "wano" 时,只需增加后缀中 k 的值即可。

示例 5:

输入:names = ["kaido","kaido(1)","kaido","kaido(1)"]
输出:["kaido","kaido(1)","kaido(2)","kaido(1)(1)"]
解释:注意,如果含后缀文件名被占用,那么系统也会按规则在名称后添加新的后缀 (k) 。

 

提示:

  • 1 <= names.length <= 5 * 10^4
  • 1 <= names[i].length <= 20
  • names[i] 由小写英文字母、数字和/或圆括号组成。

2、思路1-暴力哈希

遍历文件名数组 names,遇到不存在的文件名就将它存入哈希表与结果数组;遇到已存在的文件名就从 1 开始尝试给它加后缀,直到找到不存在的文件名,新的文件名同样需要存入哈希表与结果数组

3、代码

function getFolderNames(names: string[]): string[] {
const set = new Set();

return names.map(name => {
if (!set.has(name)) return set.add(name), name;

for (let k = 1; k; k++) {
const newName = name + `(${k})`;
if (!set.has(newName)) {
return set.add(newName), newName;
}
}
});
};

4、执行结果

image.png

5、思路2-优化哈希

上面的解法可以对内层循环进行优化,记录文件名是否存在的同时也记录它出现的次数,这样可以使得内层循环不用每次都从 1 开始

6、代码

function getFolderNames(names: string[]): string[] {
const map = new Map<string, number>();

return names.map(name => {
if (!map.has(name)) return map.set(name, 1), name;

for (let k = map.get(name); k; k++) {
const newName = name + `(${k})`;
if (map.has(newName)) continue;

map.set(name, k + 1);
map.set(newName, 1);

return newName;
}
});
};

7、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(n)O(n)

8、执行结果

image.png

· 阅读需 2 分钟

1、题干

二进制数转字符串。给定一个介于0和1之间的实数(如0.72),类型为double,打印它的二进制表达式。如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”。

示例1:

 输入:0.625
输出:"0.101"

示例2:

 输入:0.1
输出:"ERROR"
提示:0.1无法被二进制准确表示

 

提示:

  • 32位包括输出中的 "0." 这两位。
  • 题目保证输入用例的小数位数最多只有 6

2、思路1-数学模拟

将小数 num 倍乘 2,所得结果的整数部分累加到结果字符串,小数部分赋值给 num,循环上述操作直至 32 次或 num 为 0

3、代码

function printBin(num: number): string {
let ans = '0.'
while (num && ans.length <= 32) {
num = num * 2;
const k = num % 2 >> 0;
ans += k;
num -= k;
}
return ans.length > 32 ? 'ERROR' : ans;
};

4、复杂度

  • 时间复杂度: O(C)O(C)
  • 空间复杂度: O(1)O(1)

5、执行结果

image.png

6、思路2-API

调用内置API toString 实现

7、代码

function printBin(num: number): string {
const ans = num.toString(2);
return ans.length > 32 ? 'ERROR' : ans;
};

8、执行结果

image.png

· 阅读需 4 分钟

1、题干

你将会得到一份单词表 words,一个字母表 letters (可能会有重复字母),以及每个字母对应的得分情况表 score

请你帮忙计算玩家在单词拼写游戏中所能获得的「最高得分」:能够由 letters 里的字母拼写出的 任意 属于 words 单词子集中,分数最高的单词集合的得分。

单词拼写游戏的规则概述如下:

  • 玩家需要用字母表 letters 里的字母来拼写单词表 words 中的单词。
  • 可以只使用字母表 letters 中的部分字母,但是每个字母最多被使用一次。
  • 单词表 words 中每个单词只能计分(使用)一次。
  • 根据字母得分情况表score,字母 'a''b''c', ... , 'z' 对应的得分分别为 score[0], score[1], ..., score[25]
  • 本场游戏的「得分」是指:玩家所拼写出的单词集合里包含的所有字母的得分之和。

 

示例 1:

输入:words = ["dog","cat","dad","good"], letters = ["a","a","c","d","d","d","g","o","o"], score = [1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0]
输出:23
解释:
字母得分为 a=1, c=9, d=5, g=3, o=2
使用给定的字母表 letters,我们可以拼写单词 "dad" (5+1+5)和 "good" (3+2+2+5),得分为 23 。
而单词 "dad" 和 "dog" 只能得到 21 分。

示例 2:

输入:words = ["xxxz","ax","bx","cx"], letters = ["z","a","b","c","x","x","x"], score = [4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,10]
输出:27
解释:
字母得分为 a=4, b=4, c=4, x=5, z=10
使用给定的字母表 letters,我们可以组成单词 "ax" (4+5), "bx" (4+5) 和 "cx" (4+5) ,总得分为 27 。
单词 "xxxz" 的得分仅为 25 。

示例 3:

输入:words = ["leetcode"], letters = ["l","e","t","c","o","d"], score = [0,0,1,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0]
输出:0
解释:
字母 "e" 在字母表 letters 中只出现了一次,所以无法组成单词表 words 中的单词。

 

提示:

  • 1 <= words.length <= 14
  • 1 <= words[i].length <= 15
  • 1 <= letters.length <= 100
  • letters[i].length == 1
  • score.length == 26
  • 0 <= score[i] <= 10
  • words[i] 和 letters[i] 只包含小写的英文字母。

2、思路

回溯,枚举所有情况计算最高得分。未优化,存在重复计算,效率不高。

3、代码

function maxScoreWords(words: string[], letters: string[], score: number[]): number {
const wordScore = new Array(words.length).fill(0);
for (let i = 0; i < words.length; i++) {
for (let j = 0; j < words[i].length; j++) {
wordScore[i] += score[words[i][j].charCodeAt(0) - 97];
}
}

const letterDict = new Array(26).fill(0);
for (let i = 0; i < letters.length; i++) {
letterDict[letters[i].charCodeAt(0) - 97] += 1;
}

let ans = 0;
function dfs(sc: number, visited: Set<number>) {
for (let i = 0; i < words.length; i++) {
if (visited.has(i)) continue;

let valid = true;
for (let j = 0; j < words[i].length; j++) {
const c = words[i][j].charCodeAt(0) - 97;
letterDict[c]--;
if (letterDict[c] < 0) valid = false;
}

if (valid) {
ans = Math.max(ans, sc + wordScore[i]);

visited.add(i);
dfs(sc + wordScore[i], visited);
visited.delete(i);
}

for (let j = 0; j < words[i].length; j++) {
letterDict[words[i][j].charCodeAt(0) - 97]++;
}
}
}

return dfs(0, new Set()), ans;
};

4、执行结果

image.png

· 阅读需 4 分钟

1、题干

有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 "x" 和 "y",你需要通过「交换字符」的方式使这两个字符串相同。

每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。

交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i] 和 s2[j],但不能交换 s1[i] 和 s1[j]

最后,请你返回使 s1s2 相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1

 

示例 1:

输入:s1 = "xx", s2 = "yy"
输出:1
解释:
交换 s1[0] 和 s2[1],得到 s1 = "yx",s2 = "yx"。

示例 2:

输入:s1 = "xy", s2 = "yx"
输出:2
解释:
交换 s1[0] 和 s2[0],得到 s1 = "yy",s2 = "xx" 。
交换 s1[0] 和 s2[1],得到 s1 = "xy",s2 = "xy" 。
注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 "yx",因为我们只能交换属于两个不同字符串的字符。

示例 3:

输入:s1 = "xx", s2 = "xy"
输出:-1

 

提示:

  • 1 <= s1.length, s2.length <= 1000
  • s1.length == s2.length
  • s1, s2 只包含 'x' 或 'y'

2、思路

出现不同字符需要交换时有两种情况:xxyy\frac{xx}{yy}xyyx\frac{xy}{yx}

  • 情况1 xxyy\frac{xx}{yy}:只用1次对角线交换
  • 情况2 xyyx\frac{xy}{yx}:需要先上下交换再对角线交换,共计2次交换
  • 因此尽量将不同字符组合成情况1就能使交换次数最少

具体实现时,分别统计字符串 s1 中需要交换的 xy,记为 dxdy

  • dx + dy 为奇数,则无法使得两个字符串相同,返回 -1
  • dx + dy 为偶数,且 dx 也是偶数,那么不同字符可以全部组合成情况1,最小交换次数为 (dx + dy) / 2
  • dx + dy 为偶数,dx 是奇数,那么就会出现1组情况2,最小交换次数为 (dx + dy) / 2 + 1

3、代码

function minimumSwap(s1: string, s2: string): number {
let dx = 0, dy = 0;
for (let i = 0; i < s1.length; i++) {
if (s1[i] !== s2[i]) s1[i] === 'x' ? dx++ : dy++;
}

return (dx + dy) % 2 ? -1 : (dx + dy) / 2 + (dx % 2);
};

4、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

5、执行结果

image.png

· 阅读需 3 分钟

1、题干

我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]

在本题里,字母板为board = ["abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"],如下所示。

我们可以按下面的指令规则行动:

  • 如果方格存在,'U' 意味着将我们的位置上移一行;
  • 如果方格存在,'D' 意味着将我们的位置下移一行;
  • 如果方格存在,'L' 意味着将我们的位置左移一列;
  • 如果方格存在,'R' 意味着将我们的位置右移一列;
  • '!' 会把在我们当前位置 (r, c) 的字符 board[r][c] 添加到答案中。

(注意,字母板上只存在有字母的位置。)

返回指令序列,用最小的行动次数让答案和目标 target 相同。你可以返回任何达成目标的路径。

 

示例 1:

输入:target = "leet"
输出:"DDR!UURRR!!DDD!"

示例 2:

输入:target = "code"
输出:"RR!DDRR!UUL!R!"

 

提示:

  • 1 <= target.length <= 100
  • target 仅含有小写英文字母。

2、思路

根据题意模拟,关键注意 z 的路线否则会越界;任意字母到 z 的路线优先在水平方向移动,其他情况则优先在垂直方向移动

3、代码

function alphabetBoardPath(target: string): string {
let ans = '', p1 = [0, 0], p2 = [0, 0];

for (let i = 0; i < target.length; i++) {
p1 = p2;
const code = target.charCodeAt(i) - 97;
p2 = [code / 5 >> 0, code % 5];

const dx = p2[1] - p1[1], dy = p2[0] - p1[0];
const my = (dy >= 0 ? 'D'.repeat(dy) : 'U'.repeat(-dy));
const mx = (dx >= 0 ? 'R'.repeat(dx) : 'L'.repeat(-dx));

ans += (target[i] === 'z' ? mx + my : my + mx) + '!';
}

return ans;
};

4、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

5、执行结果

image.png

· 阅读需 2 分钟

1、题干

存在一种仅支持 4 种操作和 1 个变量 X 的编程语言:

  • ++XX++ 使变量 X 的值 1
  • --XX-- 使变量 X 的值 1

最初,X 的值是 0

给你一个字符串数组 operations ,这是由操作组成的一个列表,返回执行所有操作后, X最终值

 

示例 1:

输入:operations = ["--X","X++","X++"]
输出:1
解释:操作按下述步骤执行:
最初,X = 0
--X:X 减 1 ,X = 0 - 1 = -1
X++:X 加 1 ,X = -1 + 1 = 0
X++:X 加 1 ,X = 0 + 1 = 1

示例 2:

输入:operations = ["++X","++X","X++"]
输出:3
解释:操作按下述步骤执行:
最初,X = 0
++X:X 加 1 ,X = 0 + 1 = 1
++X:X 加 1 ,X = 1 + 1 = 2
X++:X 加 1 ,X = 2 + 1 = 3

示例 3:

输入:operations = ["X++","++X","--X","X--"]
输出:0
解释:操作按下述步骤执行:
最初,X = 0
X++:X 加 1 ,X = 0 + 1 = 1
++X:X 加 1 ,X = 1 + 1 = 2
--X:X 减 1 ,X = 2 - 1 = 1
X--:X 减 1 ,X = 1 - 1 = 0

 

提示:

  • 1 <= operations.length <= 100
  • operations[i] 将会是 "++X""X++""--X""X--"

2、思路

模拟

3、代码

function finalValueAfterOperations(operations: string[]): number {
let ans = 0;
for (const o of operations) {
ans += o.includes('+') ? 1 : -1;
}
return ans;
};

4、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)

5、执行结果

image.png