开锁问题

这篇博客探讨了一个开锁问题,其中涉及一个四位数的锁,每个数字轮有10个可能的槽位。锁可以从'0000'开始,并允许每个轮子加减1转动。存在一组死锁代码,使得锁会停在这些状态下无法继续转动。给定目标解锁值,博客提出了算法来计算达到目标状态所需的最小转动次数,如果无法解锁则返回-1。解题思路包括使用队列进行遍历,同时避免进入死锁状态。博客还包含了编写测试用例的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

你前面有一把锁,有四个轮子。每个轮子有10个槽:“0”、“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”。轮子可以自由旋转和环绕:例如,我们可以把’9’变成’0’,或’0’变成’9’。每一步包括转动一个轮子和一个插槽。

锁最初从“0000”开始,这是一个表示四个轮子状态的字符串。

你会得到一个死锁的列表,这意味着如果锁显示了这些代码中的任何一个,锁的轮子将停止转动,你将无法打开它。

给定一个表示将解锁的轮子的值,返回打开锁所需的最小总匝数,如果不可能,返回-1。

代码

解题思路:锁初始化是0000,每次能转动一次,所以锁的状态每次都会变化一次,4个值中的某个值加1或者是减1。所以,每个数值,都可以产生出8(4*2)种不同的值出来,这8个值又可以产生出64(8*8)种不同的值出来,这样一直下去,直到找到所需要的值或者到遍历完所有可能的值为止。在遍历查找的过程当中,我们要规避会造成死锁的某些值,并要找到循环退出的条件。

class Lock
{
public:
	int openLock(vector<string>& deadends, string target) {
		int result = -1;

		string init("0000");
		queue<string> q;
		unordered_set<string> deadendset(deadends.begin(), deadends.end());
		unordered_set<string> s;
		q.push(init);
		s.insert(init);
		while (!q.empty()) {
			++ result;
			int size = q.size();
			for (int i = 0; i < size; ++i) {
				string str = q.front();
				q.pop();
				if (target == str) {
					return result;
				}
				if (deadendset.end() == deadendset.find(str)) {
					for (unsigned j = 0; j < str.size(); ++j) {
						string case1(str);
						case1[j] = (case1[j] + 1 - 48) % 10 + 48;
						if (s.end() == s.find(case1)) {
							q.push(case1);
							s.insert(case1);
						}
						string case2(str);
						case2[j] = (case2[j] + 9 - 48) % 10 + 48;
						if (s.end() == s.find(case2)) {
							q.push(case2);
							s.insert(case2);
						}
					}
				}
			}
		}

		return -1;
	}
};

在上述代码中,我们每次遍历队列当中的数值,根据这些数据来判断是否是需要的目标值,或者是死锁的值。如果是需要的值则直接返回我们遍历的次数,否则,继续去除队列当中会造成死锁的值,把剩下的值放入到队列当中去,留着下次一起进行上述的循环判断。在这里使用了一个集体来保存已经校验过的值,免得循环一直进行( 没有找到目标值则不会退出 ),这样可以规避掉陷入死循环。

测试

example 1:
deadends = ["0201","0101","0102","1212","2002"], target = "0202"
example 2:
deadends = ["8888"], target = "0009"

根据以上的测试用例来编写测试代码:

int main()
{
	vector<string> deadends = {"0201", "0101", "0102", "1212", "2002"};
	string target("0202");
	//vector<string> deadends = { "8888"};
	//string target("0009");

	Lock lock;
	int times = lock.openLock(deadends, target);
	cout << times << endl;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Z小偉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值