字符串圈 Python面试题 构建图表:检查图是否强连通找到欧拉循环:

问题描述

给定一个大小为 N 的小写字符串 A[] 的数组,确定这些字符串是否可以链接在一起形成一个圆圈。一种 如果 X 的最后一个字符与第一个字符相同,则字符串 X 可以与另一个字符串 Y 链接在一起 Y 的字符。如果数组中的每个字符串都可以链接起来,就会形成一个圆圈。

例如对于数组 arr[] = {"for","geek","rig","kaf"},答案将是 Yes,因为给定的字符串可以链接"for","geek" and "kaf"

示例 1:

Input:
N = 3
A[] = { "abc","bcd","cdf" }
Output:
0
Explaination:
These strings can't form a circle 
because no string has 'd'at the starting index.

示例 2:

Input:
N = 4
A[] = { "ab","bc","cd","da" }
Output:
1
Explaination:
These strings can form a circle 
of strings.

我的工作正确代码

class Solution:
    def isCircle(self,N,A):
        
        visited = set()
        item1 = A[0]
        curr = item1[-1]
        visited.add(item1)
        
        for _ in range(len(A)):
            for item in A:
                if item not in visited and item[0] == curr:
                    visited.add(item)
                    curr = item[-1]
            # return visited
        if len(visited) == len(A):
            return 1
        else:
            return 0

当前时间复杂度:

O(n2)

预期时间复杂度:

O(n)

如何提高效率并在更短的时间内完成相同的工作?

解决方法

构建图表:

  • 每个字母的节点。
  • 每个单词的有向边(u,v),u是单词的第一个字母,v是最后一个字母。

就是这样,这就够了。此图中的路径代表一串单词。 (如果需要重构的话,可以把边上的词保存起来,不影响复杂度。
该图的构建成本为 O(n),因为它有 26 个顶点和 n 个边。

检查图是否强连通

观察:如果图不是强连通的,则其所有边都不可能存在循环。该检查可以通过 Tarjan's 算法在 O(V + E) 时间内完成。由于边的数量对应于我们拥有的单词数量,因此我们的目的是 O(n)。 (或者很可能更快,因为如果我们采用 a-z 字母表,我们只有 26 个顶点)

找到欧拉循环:

观察:正如我们所提到的,图中的路径是一个词链。我们正在寻找一个可以遍历所有边的循环。这是一个经过充分研究的寻找欧拉循环的问题。

由于图是强连通的,所以只要图中的所有度数都是偶数,欧拉循环就存在。检查这些边可以在与顶点数量成线性关系的时间内完成,因此它对复杂性没有任何影响,因为它们只有 26 个。如果我们去找到循环链,事情会有点困难 - 但是它可以在 O(E) 中通过例如 Hierholzer's 算法完成。
由于问题只是一个是/否决定,因此不需要找到循环。

注意:由于有关于以相同字母开头和结尾的单词的注释:这些不会改变结果,因为它们中的每一个都向图中添加了一个单节点循环,将其度增加 2。

,

实现Shamis的想法! 在 0.09 秒内运行

from collections import defaultdict

class Solution:
    def __init__(self):
        self.vertList = defaultdict(list)

    def addEdges(self,u,v):
        self.vertList[u].append(v)
        
    # <- function to generate reversed graph ->
    def reverseTheGraph(self):
        g1 = Solution()
        for v in self.vertList:
            for nbr in self.vertList[v]:
                g1.addEdges(nbr,v) # reverse graph means the edges are reversed
        return g1
    
    # <- function for normal DFS traversal ->
    def DFS(self,v1,visited2,ans):
        visited2.add(v1)
        

        for nbr in self.vertList[v1]:
            if nbr not in visited2:
                self.DFS(nbr,ans)
    
    # <- function for finished time DFS traversal ->
    def finishedTimeDFS(self,givenVertex,visited1,stack):
        visited1.add(givenVertex)
        for nbr in self.vertList[givenVertex]:
            if nbr not in visited1:
                self.finishedTimeDFS(nbr,stack)
        stack.append(givenVertex)

    # <- function to check cycle using DFS ->
    def cycleCheckDFS(self,givenV,visited,currStack,vertList):
        visited.add(givenV)
        currStack.append(givenV)
        
        for nbr in vertList[givenV]:   
        # nbr = vertList[givenV]
            if nbr in currStack:
                return True
            else:
                if nbr not in visited:
                    cycleMila = self.cycleCheckDFS(nbr,vertList)
                    if cycleMila is True:
                        return True
            currStack.pop()
        return False
    # <- the function called by the driver ->
    def isCircle(self,N,A):
        for item in A:
            first = item[0]
            last = item[-1]
            self.addEdges(first,last)
        r1 = A[0]
        givenV = r1[-1]
        stack = []
        visited1 = set()
        list1 = [ v for v in self.vertList]
        for vertices in list1:
            if vertices not in visited1:
                self.finishedTimeDFS(vertices,stack)
        reversedGraph = self.reverseTheGraph()
        visited2 = set()
        ans = []
        count = 0
        while len(stack)>0:
            curr = stack.pop()
            if curr not in visited2:
                reversedGraph.DFS(curr,ans)
                count += 1
                
            
       
        if count == 1:

        
        # <- CHECK FOR CONNECTED COMPONENT HERE ->
            r1 = A[0]
            givenV = r1[-1]
            visited3 = set()
            currStack = []
            
            result = self.cycleCheckDFS(givenV,visited3,self.vertList)
            if result == True:
                return 1
            else:
                return 0
        
        else:
            return 0

链接到在线评委 -> LINK