【数学】【深度优先搜索】【图论】【欧拉环路】753. 破解保险箱

简介: 【数学】【深度优先搜索】【图论】【欧拉环路】753. 破解保险箱

本文涉及知识点

数学 深度优先搜索 图论 欧拉环路

LeetCode753. 破解保险箱

有一个需要密码才能打开的保险箱。密码是 n 位数, 密码的每一位都是范围 [0, k - 1] 中的一个数字。

保险箱有一种特殊的密码校验方法,你可以随意输入密码序列,保险箱会自动记住 最后 n 位输入 ,如果匹配,则能够打开保险箱。

例如,正确的密码是 “345” ,并且你输入的是 “012345” :

输入 0 之后,最后 3 位输入是 “0” ,不正确。

输入 1 之后,最后 3 位输入是 “01” ,不正确。

输入 2 之后,最后 3 位输入是 “012” ,不正确。

输入 3 之后,最后 3 位输入是 “123” ,不正确。

输入 4 之后,最后 3 位输入是 “234” ,不正确。

输入 5 之后,最后 3 位输入是 “345” ,正确,打开保险箱。

在只知道密码位数 n 和范围边界 k 的前提下,请你找出并返回确保在输入的 某个时刻 能够打开保险箱的任一 最短 密码序列 。

示例 1:

输入:n = 1, k = 2

输出:“10”

解释:密码只有 1 位,所以输入每一位就可以。“01” 也能够确保打开保险箱。

示例 2:

输入:n = 2, k = 2

输出:“01100”

解释:对于每种可能的密码:

  • “00” 从第 4 位开始输入。
  • “01” 从第 1 位开始输入。
  • “10” 从第 3 位开始输入。
  • “11” 从第 2 位开始输入。
    因此 “01100” 可以确保打开保险箱。“01100”、“10011” 和 “11001” 也可以确保打开保险箱。

提示:

1 <= n <= 4

1 <= k <= 10

1 <= kn <= 4096

分析

令S是某n-1位[0,k)组成的字符串。所有的S都是节点,则每个S都有k条出边,分别连向:S.Right(n-2)+0 S.Right(n-2)+1 ⋯ \cdots S.Right(n-2)+k-1;k条入边,分别连向0+S.Right(n-2) 1+S.Right(n-2) ⋯ \cdots k-1+S.Right(n-2)。

比如:n为3,k为3

12的出边:20 21 22

12的入边:01 11 21

n =3,k=2的所有边。

每条边都至少经过一次,由于是欧拉回路,所有可以所有边都只经过一次。

最后一条边是11$\rightarrow10 则以 110 结尾。最后一条边是 11 10 则以110结尾。 最后一条边是 1110则以110结尾。最后一条边是11\rightarrow$11 则以111结尾。

由于是欧拉回路,任意起点任意方向的边数一样。我们以字典顺序最小的为起点,访问字典顺序最小的边。箭头上面是最后n个字符。

代码

核心代码

class Solution {
public:
  string crackSafe(int n, int k) {
    if (1 == n)
    {
      for (int i = 0; i < k; i++)
      {
        m_strRet += '0' + i;
      }
      return m_strRet;
    }
    m_iK = k;
    int iMask = 1;
    for (int i = 1; i < n; i++)
    {
      iMask *= k;
    }
    vector<std::queue<int>> vNeiBo(iMask);
    for (int i = 0; i < iMask; i++)
    {
      int pre = i % (iMask / k);
      for (int j = 0; j < k; j++)
      {
        vNeiBo[i].emplace(pre * k + j);
      }
    }
    DFS(vNeiBo, 0);
    m_strRet += string(n - 2, '0'); //DFS时,已经加了一个零  
    return string(m_strRet.rbegin(),m_strRet.rend());
  }
  void DFS(vector<std::queue<int>>& vNeiBo, int cur)
  {
    while (vNeiBo[cur].size())
    {
      const auto next = vNeiBo[cur].front();
      vNeiBo[cur].pop();
      DFS(vNeiBo,next);
    }
    m_strRet += '0' + cur % m_iK;
  }
  int m_iK;
  string m_strRet;
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{
  int n ,k;
  {
    Solution sln;
    n = 2, k = 2;
    auto res = sln.crackSafe(n, k);
    Assert(strlen("01100"), res.length());
  }
  {
    Solution sln;
    n = 1, k = 2;
    auto res = sln.crackSafe(n, k);
    Assert(strlen("10"), res.length());
  }
  {
    Solution sln;
    n = 3, k = 2;
    auto res = sln.crackSafe(n, k);
    Assert(strlen("0011101000"), res.length());
  }
  {
    Solution sln;
    n = 2, k = 3;
    auto res = sln.crackSafe(n, k);
    Assert(strlen("0221120100"), res.length());
  }
}

2023年4月

class Solution {
public:
void dfs(int node) {
for (int i = 0; i < m_iK; i++)
{
const int iLine = node * 10 + i;
if (m_setHasDo.count(iLine))
{
continue;
}
m_setHasDo.emplace(iLine);
dfs(iLine% m_iRange);
m_strRet += i + ‘0’;
}
}
string crackSafe(int n, int k) {
  m_iRange = pow(10, n - 1);
  m_iK = k;
  dfs(0);
  m_strRet += string(n - 1, '0');
  return m_strRet;
}
private:
unordered_set m_setHasDo;
string m_strRet;
int m_iRange;
int m_iK;
};

2024年7月

class Solution {
public:
string crackSafe(int n, int k) {
string str;
if (1 == n)
{
for (int i = 0; i < k; i++)
{
str += (i + ‘0’);
}
return str;
}
m_iNodeNum = 1;
for (int i = 1; i < n; i++)
{
m_iNodeNum *= k;
}
m_vNeiB.resize(m_iNodeNum);
for (int i = 0; i < m_iNodeNum; i++)
{
for (int j = 0; j < k; j++)
{
m_vNeiB[i].emplace((i * k + j) % m_iNodeNum);
}
}
dfs(0);
string strRet(n - 1, ‘0’);
for (int i = m_vRevVisitNode.size() - 2; i >= 0; i–)
{
strRet += m_vRevVisitNode[i]%k + ‘0’;
}
return strRet;
}
void dfs(int cur)
{
while (m_vNeiB[cur].size())
{
int first = *m_vNeiB[cur].begin();
m_vNeiB[cur].erase(first);
dfs(first);
}
m_vRevVisitNode.emplace_back(cur);
}
int m_iNodeNum;
vector<std::unordered_set> m_vNeiB;
vector m_vRevVisitNode;
};

2024年8月

class Solution {
public:
string crackSafe(int n, int k) {
if (1 == n)
{
vector vRet;
for (int i = 0; i < k; i++)
{
vRet.emplace_back(i + ‘0’);
}
vRet.emplace_back(0);
return vRet.data();
}
m_iK = k;
const int iNodeNum = pow(k, n - 1);
m_vNeiBo.resize(iNodeNum);
for (int i = 0; i < iNodeNum; i++)
{
for (int j = 0; j < k; j++)
{
m_vNeiBo[i].emplace((i * k + j)%iNodeNum);
}
}
dfs(0);
m_vRet.pop_back();
for (int i = 0; i+1 < n; i++)
{
m_vRet.emplace_back(‘0’);
}
std::reverse(m_vRet.begin(), m_vRet.end());
m_vRet.emplace_back(0);
return m_vRet.data();
}
void dfs(int cur)
{
auto& curSet = m_vNeiBo[cur];
while (curSet.size())
{
const int next = *curSet.begin();
curSet.erase(next);
dfs(next);
}
m_vRet.emplace_back(cur%m_iK+‘0’);
}
int m_iK;
vector<set> m_vNeiBo;
vector m_vRet;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关文章
|
5天前
|
算法
二分图之最大匹配数算法(Kindergarten)
二分图之最大匹配数算法(Kindergarten)
|
5天前
|
算法 测试技术 C#
【深度优化】【广度优先】【状态压缩】864. 获取所有钥匙的最短路径
【深度优化】【广度优先】【状态压缩】864. 获取所有钥匙的最短路径
|
5天前
|
机器学习/深度学习 算法 调度
拓扑排序解析:计算机与数学的交汇点以及C++ 实现
拓扑排序解析:计算机与数学的交汇点以及C++ 实现
123 0
|
5天前
|
安全 算法 测试技术
【动态规划】【广度优先】LeetCode2258:逃离火灾
【动态规划】【广度优先】LeetCode2258:逃离火灾
|
11月前
|
机器学习/深度学习 算法
最短路算法
最短路算法
41 0
|
算法 C++
蓝桥杯(聪明的猴子)克鲁斯卡尔算法最小生成树
蓝桥杯(聪明的猴子)克鲁斯卡尔算法最小生成树
70 0
|
算法
算法简单题,吾辈重拳出击 - 动态规划之爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
|
算法 定位技术
图论的灵魂——带你走进迪杰斯特拉算法的世界
图论的灵魂——带你走进迪杰斯特拉算法的世界
图论的灵魂——带你走进迪杰斯特拉算法的世界
|
机器学习/深度学习 算法
<<算法很美>>——(六)——回溯算法(下)—N皇后问题
<<算法很美>>——(六)——回溯算法(下)—N皇后问题
<<算法很美>>——(六)——回溯算法(下)—N皇后问题
|
算法
【算法竞赛进阶指南】关押罪犯(二分+染色法判断二分图)
【算法竞赛进阶指南】关押罪犯(二分+染色法判断二分图)
62 0