514. Freedom Trail 【Hard】 动态规划

问题:给定一个圆环(初始字符为第一个)和一个字符串,进行如下操作直至打印出此字符串——

操作一:打印出圆环的第一个字符

操作二:把圆环顺时针或逆时针转一个位置

问打印此字符串最少需要多少步操作?


思路:用动归解决。将字符串拆分为单个字符,每一轮只考虑当前要打印的字符(假设为X)——对圆环上的每个X,求出其从上一轮到这一轮的最小距离dist(X)。

距离指圆环上的顺时针or逆时针最短距离。

如果是第一轮,那么每个X的dist(X)为它的位置到0的距离再加一(加一是因为要打印)

如果是第N轮(N>1),假设上一轮要打印的字符为S(则每个S都在上一轮都已经有一个dist值了),那么每个X的dist(X)为:它的位置到圆环上各个S的距离分别加上dist(S)的最小值,再加一(加一是因为要打印)

最终动归出最后一个字符Z,在dist(Z)中找到最小值打印出来就可以了。


难度还可以,主要是明确了思路就好了,时间都花在了debug上面。


vector<int> max_vector_initializer(100, 9999999);

int min_num(int x, int y) {
	if (x > y) return y;
	else return x;
}

int abs(int d) {
	if (d > 0) return d;
	else return -d;
}

int C2I(char c) {
	return (int)(c - 'a');
}


int dist(int p1, int p2, int lr) {
	int abs_dis = abs(p1 - p2);
	return min_num(abs_dis, lr - abs_dis);
}


class Solution {
public:
    int findRotateSteps(string ring, string key) {

        vector<int> mapping[26];
	int lr = ring.size();
	int lk = key.size();
	int pos;
	for (int i = 0; i < lr; ++i) {
		pos = C2I(ring[i]);
		mapping[pos].push_back(i);
	}
        
        vector<int> a(100, 9999999);
        vector<int> b(100, 9999999);
	for (int it = 0; it < lk; ++it) {
            b = a; // b is the previous state
            a = max_vector_initializer; // initialize a to a max vector

            int prev, next, d;
            int prev_c = (it == 0 ? -1 : C2I(key[it - 1]));
            int next_c = C2I(key[it]);
            if (prev_c == -1) {
                for (int j = 0; j < mapping[next_c].size(); ++j) {
                    next = mapping[next_c][j];
                    a[next] = dist(0, next, lr) + 1;
                }
            } else {
                for (int i = 0; i < mapping[prev_c].size(); ++i) {
                    for (int j = 0; j < mapping[next_c].size(); ++j) {
                        prev = mapping[prev_c][i];
                        next = mapping[next_c][j];
                        d = dist(prev, next, lr);
                        a[next] = min_num(a[next], b[prev] + 1 + d);
                    }
                }
            }
	}
        
        
        int pos_c = C2I(key[lk - 1]);
        int _min_ = 9999999;
        for (int i = 0; i < mapping[pos_c].size(); ++i) {
            pos = mapping[pos_c][i];
            if (_min_ > a[pos]) {
                _min_ = a[pos];
            }
        }
        return _min_;

    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值