#拓扑排序
题目描述
现有一种使用英语字母的火星语言,这门语言的字母顺序与英语顺序不同。给你一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 “” 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。 字符串 s 字典顺序小于 字符串 t 有两种情况: 1.在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。 2.如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。
1 2 3 4 5 6 7 8 9 10 11 12 示例 1: 输入:words = ["wrt","wrf","er","ett","rftt"] 输出:"wertf" 示例 2: 输入:words = ["z","x"] 输出:"zx" 示例 3: 输入:words = ["z","x","z"] 输出:"" 解释:不存在合法字母顺序,因此返回 "" 。
解题思路 (1). 首先考虑什么情况下会出现不合法的情况:如果在之前判断字母 ‘x’ 的字典序应该大于 ‘y’,可是在后面又出现了 ‘y’ 的字典序应该大于 ‘x’ 的情况,那么此时就出现了矛盾,因此是不合法的; (2). 对于这种只允许单向依赖的情况,考虑使用拓扑排序。首先就要构建邻接表和入度统计。在建立邻接表的时候要考虑一种情况,那就是如果出现在后面的字符串是前面字符串的前缀字符串,那么可以立即判定是不合法的; (3). 在构建好两个数据结构后,使用广度优先搜索查找。将入度为 0 的字母放入队列中,然后再将其对应的邻接表中的字母入度减一,此时相当于在拓扑排序中消除了对该字母的依赖,也可以看作访问数 visited
加 1; (4). 最后判断一下 visited
是否是全体出现过的字母数,相等则说明是一个拓扑排序,不存在循环依赖。
时间复杂度 O(words.length*words[i].length)
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 func alienOrder (words []string ) string { adjacency := make (map [byte ][]byte ) inDegree := make (map [byte ]int ) ret := "" var buildGraph func () bool buildGraph = func () bool { for i:=0 ; i<len (words); i++ { for j:=0 ; j<len (words[i]); j++ { adjacency[words[i][j]] = []byte {} } } for i:=1 ; i<len (words); i++ { w1, w2 := words[i-1 ], words[i] j := 0 minLength := min(len (w1),len (w2)) for ; j<minLength; j++ { if w1[j] != w2[j] { adjacency[w1[j]] = append (adjacency[w1[j]], w2[j]) inDegree[w2[j]]++ break } } if j == minLength && len (w1) > len (w2) { return false } } return true } var visitedCount func () int visitedCount = func () int { visited := 0 q := []byte {} for k,_ := range adjacency { if inDegree[k] == 0 { q = append (q, k) } } for len (q) > 0 { p := []byte {} for i:=0 ; i<len (q); i++ { w := q[i] for j:=0 ; j<len (adjacency[w]); j++ { x := adjacency[w][j] inDegree[x]-- if inDegree[x] == 0 { p = append (p, x) } } visited++ } ret += string (q) q = p } return visited } if !buildGraph() || visitedCount() != len (adjacency) { return "" } return ret } func min (a,b int ) int { if a < b { return a } return b }
#模拟题
题目描述
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 1.读入字符串并丢弃无用的前导空格 2.检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。 3.读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。 4.将前面步骤读入的这些数字转换为整数(即,”123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。 5.如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。 6.返回整数作为最终结果。
注意: 本题中的空白字符只包括空格字符 ‘ ‘ 。 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 示例 1: 输入:s = "42" 输出:42 解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。 第 1 步:"42"(当前没有读入字符,因为没有前导空格) ^ 第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^ 第 3 步:"42"(读入 "42") ^ 解析得到整数 42 。 由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。 示例 2: 输入:s = " -42" 输出:-42 解释: 第 1 步:" -42"(读入前导空格,但忽视掉) ^ 第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数) ^ 第 3 步:" -42"(读入 "42") ^ 解析得到整数 -42 。 由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。 示例 3: 输入:s = "4193 with words" 输出:4193 解释: 第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格) ^ 第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+') ^ 第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止) ^ 解析得到整数 4193 。 由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。 提示: 0 <= s.length <= 200 s 由英文字母(大写和小写)、数字(0-9)、' '、'+'、'-' 和 '.' 组成
解题思路 (1). 这是一道很典型的模拟题,对于模拟题,少不了条件判断,建议采用 switch 来代替大量的 if…else,这样代码的逻辑会清晰很多; (2). 这道题唯一值得关心的点就是越界问题,那么就需要将合法数字字符串取出后先去除前导零,然后再根据符号分别判断是否越界。
时间复杂度 O(N)
解题代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 func myAtoi (s string ) int { if len (s) == 0 { return 0 } isNeg := false prefixLetter := true str := []byte {} maxNum, minNum := math.MaxInt32, -1 *math.MinInt32 for i:=0 ; i<len (s); i++ { if prefixLetter { switch { case s[i] == '-' : isNeg = true prefixLetter = false case s[i] == '+' : prefixLetter = false case s[i] == ' ' : case s[i] == '.' || (s[i] >= 'a' && s[i] <= 'z' ): return 0 case s[i] >= '0' && s[i] <= '9' : prefixLetter = false str = append (str, s[i]) } } else { switch { case s[i] >= '0' && s[i] <= '9' : str = append (str, s[i]) default : i = len (s) } } } if len (str) == 0 { return 0 } x := 0 for i:=0 ; i<len (str); i++ { if str[i] != '0' { x = i break } } ret := 0 if !isNeg { for i:=x; i<len (str) ;i++ { ret *= 10 ret += int (str[i])-'0' if ret > maxNum { return maxNum } } } else { for i:=x; i<len (str); i++ { ret *= 10 ret += int (str[i])-'0' if ret > minNum { return math.MinInt32 } } ret *= -1 } return ret }