继续「快刷四部曲」5 分钟速刷 315 题(格式化字符串)。
核心一句话:按 sublen 切分后,把相邻的奇-偶对(第 2k-1 与 2k 块)互换即可。
① 抽象模型
- 已知 sublen 之和必等于 str.length(),无需校验。
- 把 str 拆成若干段,每段长度由 sublen[i] 决定。
- 对调规则:
块 0 ↔ 块 1
块 2 ↔ 块 3
...
最后若剩奇数块,则最后一块不动。
② 最优算法
时间 O(n):只扫一遍。
空间 O(n):新建 char[] 保存结果,避免大量 substring。
算法:
- 用双指针:srcPos 指向原串当前段首,dstPos 指向新串当前写入位置。
- 步长 2 遍历 sublen 数组:
- 先记下第 i 段长度 L1 = sublen[i]
- 若 i+1 存在,记下 L2 = sublen[i+1]
- 先把原串 [srcPos+L1, srcPos+L1+L2) 这段(即第 i+1 块)拷到新串 dstPos 处,dstPos += L2
- 再把原串 [srcPos, srcPos+L1) 这段(即第 i 块)拷到新串 dstPos 处,dstPos += L1
- srcPos += L1 + L2
- 最后若 sublen 长度为奇数,把最后一块直接拷完即可。
③ 边界/异常
- sublen 长度为 0 已隐含不可能(题目保证和为 str.length() 且 ≥1)。
- 空串 ⇒ 返回空串。
④ 代码(Java,可直接粘 LintCode)
java
public String formatString(String str, int[] sublen) {
int n = str.length();
char[] s = str.toCharArray();
char[] ans = new char[n];
int srcPos = 0, dstPos = 0;
for (int i = 0; i < sublen.length; i += 2) {
int L1 = sublen[i];
int L2 = (i + 1 < sublen.length) ? sublen[i + 1] : 0;
// 先写第二段
if (L2 > 0) {
System.arraycopy(s, srcPos + L1, ans, dstPos, L2);
dstPos += L2;
}
// 再写第一段
System.arraycopy(s, srcPos, ans, dstPos, L1);
dstPos += L1;
srcPos += L1 + L2;
}
return new String(ans);
}
复杂度:
时间 O(n),空间 O(n)。
写完,Submit,一遍 AC。