leetcode 514. Freedom Trail(自由之路)

In the video game Fallout 4, the quest “Road to Freedom” requires players to reach a metal dial called the “Freedom Trail Ring”, and use the dial to spell a specific keyword in order to open the door.

Given a string ring, which represents the code engraved on the outer ring and another string key, which represents the keyword needs to be spelled. You need to find the minimum number of steps in order to spell all the characters in the keyword.

Initially, the first character of the ring is aligned at 12:00 direction. You need to spell all the characters in the string key one by one by rotating the ring clockwise or anticlockwise to make each character of the string key aligned at 12:00 direction and then by pressing the center button.

At the stage of rotating the ring to spell the key character key[i]:

You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. The final purpose of the rotation is to align one of the string ring’s characters at the 12:00 direction, where this character must equal to the character key[i].
If the character key[i] has been aligned at the 12:00 direction, you need to press the center button to spell, which also counts as 1 step. After the pressing, you could begin to spell the next character in the key (next stage), otherwise, you’ve finished all the spelling.
Example:

在这里插入图片描述

Input: ring = “godding”, key = “gd”
Output: 4
Explanation:
For the first key character ‘g’, since it is already in place, we just need 1 step to spell this character.
For the second key character ‘d’, we need to rotate the ring “godding” anticlockwise by two steps to make it become “ddinggo”.
Also, we need 1 more step for spelling.
So the final output is 4.

一个字符串ring,首字符在12点方向,它可以顺时针或逆时针转,要转出字符串key中的所有字符,每转出一个字符,按一下中间按钮。
转盘转动时,每经过一个字符算一个step,按中间按钮也算一个step。
问最终转出key至少要经过多少step

思路:
参考方法

转盘的转动要靠想象了,假设字符串ring的长度是R,刚开始在12点处的应该是index=0的位置,假设现在想转到key的第一个字符G,可以就保持不动直接就是G,也可以逆时针转一位。就是说有两个G可以转,那么需要先标记每个G在什么位置,比如说在位置 i,那么顺时针转到i就需要i step,逆时针就需要R-i step。这是G转到key的index0的一步,记为dp[G][0], 因为G有两个位置,要遍历这两个位置,选出较小的一个,因此dp[G][0] = min(i, R-i) + 1, 加1是要按中间那个按钮

上面是第一步,后面的就需要知道上一步在哪个位置了,假设上一步在pre_i, 这一步就是cur_i, 遍历上一步所有可能的位置,求dp[pre_i][cur_i],
从pre_i顺时针到cur_i的step数是abs(pre_i - cur_i), 逆时针是R - abs(pre_i-cur_i) ,这两者选出较小的,当然这选出的只是遍历到的一个位置的较小值,最终的 dp[pre_i][cur_i] 要从遍历的所有里面选出最小值

当cur_i是key的最后一个字符的时候,就把从遍历pre_i中选出的最小值作为结果。

因为字母只有26个,可以给每个字母出现在ring中的位置提前保存起来,便于后面使用。

    public int findRotateSteps(String ring, String key) {
        if(ring == null || key == null) {
            return 0;
        }
        
        int R = ring.length();
        int K = key.length();
        int result = Integer.MAX_VALUE;
        
        int[][] dp = new int[R][K];
        List<List<Integer>> char_pos = new ArrayList<>();
        
        for(int i = 0; i < 26; i++) {
            char_pos.add(new ArrayList<Integer>());
        }
        
        for(int i = 0; i < R; i++) {
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        }
        
        for(int i = 0; i < R; i++) {
            //key中每个char对应的位置
            char_pos.get(ring.charAt(i)-'a').add(i);
        }
        
        for(int i = 0; i < K; i++) {
            int cur = key.charAt(i) - 'a';
            for(Integer cur_pos : char_pos.get(cur)) {
                if(i == 0) {
                    dp[cur_pos][0] = Math.min(cur_pos, R - cur_pos) + 1;
                } else {
                    int pre = key.charAt(i-1) - 'a';
                    for(Integer pre_pos : char_pos.get(pre)) {
                        int diff = Math.min(Math.abs(pre_pos - cur_pos), 
                                            R - Math.abs(pre_pos-cur_pos));
                        dp[cur_pos][i] = Math.min(dp[cur_pos][i], 
                                                  dp[pre_pos][i-1]+diff+1);
                                                 
                    }
                }
                if(i == K-1) {
                    result = Math.min(result, dp[cur_pos][i]);
                }
            }
        }
        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值