
2026-02-22:删除子字符串后不同的终点。用go语言,给你一个只包含字符 U、D、L、R 的字符串 s,用来表示在无限的二维格点上每一步的方向(U 向上,D 向下,L 向左,R 向右)。另有一个正整数 k。
你需要从 s 中取出并删掉一段长度为 k 的连续字符(只能删一次)。随后从起点 (0,0) 出发,按删掉这段之后剩余的字符顺序执行移动。
问:在允许任意选择删掉位置的情况下,可能得到的不同终点坐标共有多少个?
1 <= s.length <= 100000。
s 只包含 'U'、'D'、'L' 和 'R'。
1 <= k <= s.length。
输入:s = "LUL", k = 1。
输出:2。
解释:
移除长度为 1 的子字符串后,s 可以是 "UL"、"LL" 或 "LU"。执行这些移动后,最终坐标将分别是 (-1, 1)、(-2, 0) 和 (-1, 1)。有两个不同的点 (-1, 1) 和 (-2, 0),因此答案是 2。
题目来自力扣3694。
要理解这段代码的逻辑,首先需要把“删除一段长度为k的子串后走剩余路径的终点”这个问题,转化为更易计算的数学等价问题,以下是详细步骤:
题目要求“删除长度为k的连续子串,走剩余字符得到终点”,我们可以把路径拆分为三部分:
[0...n-1](n是字符串长度)[i...i+k-1]这段子串,剩余路径就是[0...i-1] + [i+k...n-1]从坐标变化的角度,剩余路径的终点 = 前i步的总位移 + 从i+k到末尾的总位移。 而代码中用了更巧妙的等价计算: 总位移(走完全部字符)= 前i步位移 + 被删除的k步位移 + 后段(i+k到末尾)位移 → 剩余路径终点 = 总位移 - 被删除的k步位移
这个转化是核心:不用模拟删除后的路径,只需计算“总位移减去任意一段长度为k的连续子串的位移”,结果就是删除该子串后的终点。
pair{0,0}表示初始坐标(起点),对应“删除第一段长度为k的子串(即前k个字符)”时的被删除位移(初始为0,因为还没计算任何字符)。代码用滑动窗口(长度为k)遍历所有可能的k长度子串,计算每个子串的总位移:
以题目示例为例,拆解执行过程:
以示例s="LUL"为例,总位移计算:
len(s)-k次循环,每次循环仅做常数次操作(加减坐标、存入map)→ O(n)(n是字符串长度)。n-k+1个不同的pair(最坏情况所有k长度子串的位移都不同)→ O(n)。.
package main
import (
"fmt"
)
type pair struct{ x, y int }
var dirs = []pair{'L': {-1, 0}, 'R': {1, 0}, 'D': {0, -1}, 'U': {0, 1}}
func distinctPoints(s string, k int)int {
p := pair{}
set := map[pair]struct{}{p: {}} // 第一个窗口
for i := k; i < len(s); i++ {
in, out := s[i], s[i-k]
p.x += dirs[in].x - dirs[out].x
p.y += dirs[in].y - dirs[out].y
set[p] = struct{}{}
}
returnlen(set)
}
func main() {
s := "LUL"
k := 1
result := distinctPoints(s, k)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def distinct_points(s: str, k: int) -> int:
# 定义方向映射
dirs = {'L': (-1, 0), 'R': (1, 0), 'D': (0, -1), 'U': (0, 1)}
# 初始化位置和集合
x, y = 0, 0
points = {(x, y)} # 第一个窗口
for i in range(k, len(s)):
in_char, out_char = s[i], s[i - k]
# 更新位置:加上新字符的移动,减去移出窗口的字符的移动
dx_in, dy_in = dirs[in_char]
dx_out, dy_out = dirs[out_char]
x += dx_in - dx_out
y += dy_in - dy_out
points.add((x, y))
returnlen(points)
def main():
s = "LUL"
k = 1
result = distinct_points(s, k)
print(result)
if __name__ == "__main__":
main()
.
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
struct Pair {
int x, y;
// 为了能作为unordered_set的key,需要定义相等比较和哈希函数
bool operator==(const Pair& other) const {
return x == other.x && y == other.y;
}
};
// 为Pair类型提供哈希函数
namespace std {
template<>
struct hash<Pair> {
size_t operator()(const Pair& p) const {
return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1);
}
};
}
int distinctPoints(const std::string& s, int k) {
// 定义方向映射
std::unordered_map<char, Pair> dirs = {
{'L', {-1, 0}},
{'R', {1, 0}},
{'D', {0, -1}},
{'U', {0, 1}}
};
Pair p = {0, 0};
std::unordered_set<Pair> points;
points.insert(p); // 第一个窗口
for (int i = k; i < s.length(); i++) {
char in = s[i];
char out = s[i - k];
p.x += dirs[in].x - dirs[out].x;
p.y += dirs[in].y - dirs[out].y;
points.insert(p);
}
return points.size();
}
int main() {
std::string s = "LUL";
int k = 1;
int result = distinctPoints(s, k);
std::cout << result << std::endl;
return0;
}

·
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。
·