leetcode:269. 火星词典

这篇博客介绍了如何利用图论和拓扑排序解决LeetCode和LintCode上的269题——火星词典。通过分析给定的单词列表,找出并建立字母间的顺序关系,然后通过消除环并进行拓扑排序来确定火星语言的字母顺序。博客提供了详细的解题思路,包括构建字母关系图和执行拓扑排序的过程,还给出了具体的C++实现代码。
摘要由CSDN通过智能技术生成

题目来源

题目描述

现有一种使用英语字母的火星语言,这门语言的字母顺序与英语顺序不同。

给你一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。

请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 “” 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。

字符串 s 字典顺序小于 字符串 t 有两种情况:

  • 在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
  • 如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。

示例 1:

输入:words = [“wrt”,“wrf”,“er”,“ett”,“rftt”]
输出:“wertf”
示例 2:

输入:words = [“z”,“x”]
输出:“zx”
示例 3:

输入:words = [“z”,“x”,“z”]
输出:“”
解释:不存在合法字母顺序,因此返回 “” 。

提示:

1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] 仅由小写英文字母组成

题目解析

思路

  • 可以先根据word生成一张图
    • 比较相邻两个words,逐个比较两个words相同位置的字符,直到找到第一个字符不相同的位置
    • 这个位置的两个字符我们可以获得有效信息,也就是这两个字符在alien order中的相对顺序
    • 需要注意的是也就是这个位置有用,因为后面的不同位置我们无法获取任何信息。
  • 然后看拓扑排序,不能有环

举个例子

比如题目中给的例子1,可以推出的顺序关系有

t->f
w->e
r->t
e->r

实现

class Solution {
public:
    std::string alienOrder(vector<std::string>& words) {
       if(words.empty()){
           return "";
       }

       int N = words.size();
       // 将出现过的字符的入度设定为0
       // 没有出现的字母入度为-1,出现了的字母的入度为非负数
       std::map<char, int> indegree;
        for (int i = 0; i < N; ++i) {
            for(char ch : words[i]){
                indegree[ch] = 0;
            }
        }

        std::map<char, std::set<char>> graph;
        for (int i = 0; i < N - 1; ++i) {
            std::string curr = words[i];
            std::string next = words[i + 1];
            int len = std::min(curr.length(), next.length());
            int j = 0;
            for(;j < len; j++){
                //  # 保存第一个不同的字符顺序,位于前面的字母作为key,位于后面的字母存到set中作为值
                if(curr[j] != next[j]){
                   if(!graph[curr[j]].count(next[j])){
                       graph[curr[j]].emplace(next[j]);
                       indegree[next[j]]++;
                   }
                   break;
                }
            }
/*
  ab, abc
*/
            // a 的字母排列顺序优先于 b,那么在给定的词典当中 a 定先出现在 b 前面
            if(j < curr.length() && j == next.length()){
                return "";  //前面都一样,cur字符更长,next没有字符了----说明给出的字典就不对
            }
        }

        std::queue<char> q;
        for(auto it : indegree){
            char key = it.first;
            if(indegree[key] == 0){
                q.push(key);
            }
        }

		std::string ans;
        while (!q.empty()){
            char curr = q.front(); q.pop();
            ans += curr;
            if(graph.count(curr)){
                for(char next : graph[curr]){
                    --indegree[next];
                    if(indegree[next] == 0){
                        q.push(next);
                    }
                }
            }
        }

        return ans.length() == indegree.size() ? ans : "";
    }
};

测试

int main() {
    std::vector<std::string> vec {"wrt",
                                  "wrf",
                                  "er",
                                  "ett",
                                  "rftt"};

    Solution a;
    auto v =  a.alienOrder(vec) ;
    printf("%s\n", v.c_str());
    return 1;
}

类似题目

题目思路
207. 课程表(是否能完成所有课程的学习 )是否有环
269. 火星词典
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值