Leetcode 每日一题:Crack The Safe

写在前面:

学期真的忙起来了,我的两个社团也在上一周终于完成了大部分招新活动。虽然后面有即将到来的期中考试和求职,但希望能有时间将帖子的频率提上去吧(真的尽量因为从做题思考到写博客讲解思路需要大量的时间,在勤工俭学打工的多方压力下尽量保证更新频率)~~

今天我带来的依旧是一个 Graph Theory 图论的问题,也是一道非常典型又不典型的类型。典型是说这道题目有一个专门的算法,De Bruijn 算法。 不典型的一点是如果不知道这个算法,基本不太可能想到可以用 Graph Theory 解决,且就算用到了 graph theory,也会很难 come up 一个 solutions,就染我们一起来看看,也一起来学习一下这个这个 De Bruijn sequence 的算法吧!

题目介绍:

题目信息:

题目问题:

  • 有一个系统被一串数字组成的密码锁保护,密码长度为 n (将会被给到),密码的数大于等于0,小于 k(将会被给到)
  • 检查密码的机制是,他只会检查最后输入的 n 项,如果当前 n 项 成功 match 密码,密码锁将会被破解
  • 给定 n 和 k
  • 返回一个 最小长度的 sequence,这个sequence 将满足,在我们从左到右依次输入时,我们会在某一次输入的时候输入到正确的密码组合
  • 返回任意满足的 sequence 都可,尝试到正确密码的早晚不影响结果

题目想法:

如何将抽象问题转化为实际问题:

首先,根据这个题目的真实密码由 n 个 不大于 k 的正整数组成,再到我们需要一个 sequence,让其能保证我们能在某一次尝试中尝试到密码,所以我们的这个 sequence 应该就需要包涵所有的 n 个 不大于 k 的正整数所能组成集合。

举例:

在 n = 2,k = 2 的时候,可能的密码就是 00, 01, 10, 11,如果我们的 sequence 包含所有的可能组合,如 '00011011' 那我们这个sequence就可以在某一刻尝试出真正的密码

所以,这个问题的首先关键就是,我们需要找到在给定 n,k 下所有满足条件的组合,并将他们组合成一个 sequence,这样就能保证我们一定能包含真正的密码。但是,这样并不是最短的

De Bruijn 数列:

因为题目不仅需要找出满足条件的 sequence,同时要求我们用最短的长度解决这个问题,而满足能将所有组合全部记录下来并且最短长度的数列就是 De Bruijn 数列

De Brujin 数列 (n = 2, k = 2) of '000111011' is '00110

De Brujin 数列的形成原理就是:我们总是能够利用上一个位置的数去组合成一个新的组合,从而将所需要的长度缩减一半:

比如 "00" 和 "01" 两个组合,实际上可以写成 "001",第二个组合的时候我们借用上一个组合的其中一个字母同样可以完成生成。因此,这道题目就转化为了,求出在 给定 n 和 k 之下的 De Bruijn 数列

如何求出 De Bruijn 结果:

我们将使用 DFS 算法求出 我们所需要的 De Bruijn 结果。具体思路是:

  • 创建一个初始位 n 的全 0 string,这个就是我们的第一个 组合,都是 0
  • 然后每次遍历到下一个数字:
    • 如果我们已经遍历了所有的可能性,意味着我们已经找到了 De Bruijn 答案,返回 true
    • 我们尝试 0 到 k 的所有组合尝试,并且从头拿掉一个数,这样能保证我们正在观察的这个substring + 新的char 是一个合理的 combination。针对每一个组合尝试:
      • 如果这个新组合还没有被遍历过,以这个组合继续遍历向下
      • 如果返回 true,则直接返回
      • 如果失败,则 move on 去下一个组合继续尝试
    • 最后返回的结果,是在遍历结束后所有成功的组合的数列,也就是我们的 De Bruijn 数列

题目代码:

cpp 复制代码
class Solution {
public:
    int total;
    int n;
    int k;
    
    bool DFS(unordered_map<string, bool>& visited, string& ans){
        // if we finish traverse all nodes, return true since we find it
        if(visited.size() == total){
            return true;
        }
        
        // try each possible choice and see if it can yield a complete path
        for(int i = 0; i < k; i++){
            ans += to_string(i);
            // the cur word is a new combination that we can form, and we want to make sure its unique
            string cur = ans.substr(ans.size() - n);
            
            if(!visited.contains(cur)){
                visited[cur] = true;
                // if there is successful try, automatically refer back
                if(DFS(visited, ans)){
                    return true;
                }
                
                //backtracking and reset
                visited.erase(cur);
            }
            //backtracking, remove the char behind
            ans.pop_back();
        }
        
        // there will be no way to find it, return false
        return false;
    }
    
    string crackSafe(int n, int k) {
        //this is the total amount of choice for free choice n spot, where each spot as k choice
        total = pow(k, n);
        this->k = k;
        this->n = n;
        
        //start with the a sequence with length n and all 0, since we always has all choose 0 choice
        string ans(n, '0');
        unordered_map<string, bool> visited;
        visited[ans] = true;
        
        DFS(visited, ans);
        return ans;
    }
};
相关推荐
软工菜鸡22 分钟前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
南宫生24 分钟前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
AI视觉网奇1 小时前
sklearn 安装使用笔记
人工智能·算法·sklearn
JingHongB1 小时前
代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
算法·深度优先·图论
weixin_432702261 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
小冉在学习1 小时前
day52 图论章节刷题Part04(110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长 )
算法·深度优先·图论
Repeat7151 小时前
图论基础--孤岛系列
算法·深度优先·广度优先·图论基础
小冉在学习1 小时前
day53 图论章节刷题Part05(并查集理论基础、寻找存在的路径)
java·算法·图论
武子康2 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
passer__jw7672 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode