一个字符串 ring ,表示刻在外环上的编码;给定另一个字符串 key ,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。
最初,ring 的第一个字符与 12:00 方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。
旋转 ring 拼出 key 字符 key[i] 的阶段中:
您可以将 ring 顺时针或逆时针旋转 一个位置 ,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i] 。
如果字符 key[i] 已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。
对于字符串key,每一位都需要一次确定,字符串ring总共n位,当前位置i,最多需要向前或向后搜索n/2次
int findRotateSteps(char* ring, char* key) {
int r = 0, count = 0;
int i = 0, j = 0, k = 0, n = 0;
r = strlen(ring);
k = strlen(key); //求字符串长度
count = k;
for (n = 0; n < k; n++) { //对key的每个字母
printf(" %c", key[n]);
//当前ring[i]
for (j = 0; j <= r / 2; j++) { //转j次
if (ring[(i + j) % r] == key[n]) {
printf("%d",j);
count += j;
i = (i + j) % r;
printf("%c",ring[i]);
break;
}
if (ring[(r + i - j) % r] == key[n]) {
printf("%d",j);
count += j;
i = (r + i - j) % r;
printf("%c",ring[i]);
break;
}
}
}
return count;
}
解答错误实例
ring=“nyngl”
key=“yyynnnnnnlllggg”
由于n可以向前也可以向后,但是到l最近的n应该向前的n
定义 dp[i][j]表示从前往后拼写出 key的第 i个字符, ring的第 j个字符与 12:00方向对齐的最少步数(下标均从 0开始)。
显然,只有当字符串 ring的第 j个字符需要和 key的第 i个字符相同时才能拼写出 key的第 i个字符,因此对于 key的第 i个字符,需要考虑计算的 ring的第 j个字符只有 key[i]在 ring中出现的下标集合。我们对每个字符维护一个位置数组 pos[i],表示字符 i在 ring中出现的位置集合,用来加速计算转移的过程。
对于状态 dp[i][j],需要枚举上一次与 12:00方向对齐的位置 k,因此可以列出如下的转移方程:
dp[i][j]=mink∈pos[key[i−1]]{dp[i−1][k]+min{abs(j−k),n−abs(j−k)}+1}
其中 min{abs(j−k),n−abs(j−k)}+1表示在当前第 k个字符与 12:00方向对齐时第 j个字符旋转到 12:00方向并按下拼写的最少步数。
最后答案即为 mini=0n−1{dp[m−1][i]}。
这样的做法需要开辟 O(mn)的空间来存放 dp值。考虑到每次转移状态 dp[i][]只会从 dp[i−1][]转移过来,因此我们可以利用滚动数组优化第一维的空间复杂度,有能力的读者可以尝试实现。下面只给出最朴素的 O(mn)空间复杂度的实现。
int findRotateSteps(char* ring, char* key) {
int n = strlen(ring), m = strlen(key);
int pos[26][n], posSize[26];
memset(posSize, 0, sizeof(posSize));
for (int i = 0; i < n; ++i) {
int x = ring[i] - 'a';
pos[x][posSize[x]++] = i;
}
int dp[m][n];
memset(dp, 0x3f3f3f3f, sizeof(dp));
for (int i = 0; i < posSize[key[0] - 'a']; i++) {
int x = pos[key[0] - 'a'][i];
dp[0][x] = fmin(x, n - x) + 1;
}
for (int i = 1; i < m; ++i) {
for (int j = 0; j < posSize[key[i] - 'a']; ++j) {
int x = pos[key[i] - 'a'][j];
for (int k = 0; k < posSize[key[i - 1] - 'a']; ++k) {
int y = pos[key[i - 1] - 'a'][k];
dp[i][x] = fmin(dp[i][x], dp[i - 1][y] + fmin(abs(x - y), n - abs(x - y)) + 1);
}
}
}
int ret = dp[m - 1][0];
for (int i = 1; i < n; ++i) {
ret = fmin(ret, dp[m - 1][i]);
}
return ret;
}