说起 queue 大家都很熟悉,可能是除了 number,string 后最熟悉的一种数据结构。毕竟谁还没用过 array 呢?但可不要小瞧这 array,很多 queue 的题目都是 medium,需要仔细的思考才能高效地答出来。
今天的一道小题是在多年前遇到的:
给出一个电话拨号盘和一个单词 dictionary,返回输入数字的所有合法字符串的组合。
Input:dictionary = {'AD', 'CD', 'BE', 'BF', 'CE', 'DF'}23Output:{'AD', 'BF', 'CE'}
刚拿到这题时仔细分析发现,可以拆分为两步。
1)将所有输入字符的组合穷举出来
2)再用 dictionary 查,返回已经在里面的即可
我当时最初的想法就是 combination 排列。分别从每一个按键上取一个数字,然后组成所需要的字符串。例如这样
2 {'A', 'B', 'C'}3 {'D', 'E', 'F'}=> AD AE AF BD BE BF CD CE CF
貌似还可以,但如果 3 个数字或者 4 个,5 个呢?该怎么写代码,而且冥冥之中感觉复杂度也高得吓人。我当时就是挂在了这里。
后来下来研究发现这题的考察重点实际上是 queue 的用法。因为按键是有顺序的,先按下去的键值先处理,正好符合 first-in,first-out => queue 的特性。
first-in,first-out
还是拿 23 来举例。
首先在 queue 里放入键值 2 所表示的值。
queue = ['A', 'B', 'C']
然后取最开始输入的 'A',并与数值 3 所表示的值合并,并把新的值放入 queue。
queue = ['B', 'C', 'AD', 'AE', 'AF']
依次类推来执行 B 直到所有的字母都被执行完毕。
推理图
基本算法已经确定,接下来就是实现细节和一些 corner cases。
首先我们需要建立一个 map 把数字和其值对应起来。其次处理好字符的循环关系。具体看一下代码片段
// pseudo codemap = [ '', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz',]queue = ['']; // needs to have an empty herefor(i, 0 -> input.length){ n = parseInt(input[i]); chars = map[n]; // make sure each around it will go level by level while(queue[0].length == i){ first = queue.shift(); for(s of chars){ queue.push(first + s); } }}for(s of queue){ if(dictionary.has(s)){ ... }}
这里的重点有两个
1)放入一个空字符到 queue 这样才可以正确的开始循环
2)巧妙利用 while(queue[0].length == i) 来判断当前按钮是否已经全部遍历完毕
例如
i = 0 queue=[''] => queue=['A', 'B', 'C']
i = 1 queue=['A', 'B', 'C'] => queue=['B', 'C', 'AD', ...]
i = 2
总结,通过利用 queue 的 first-in first-out 特性,我们将此问题巧妙解决。不仅高效,而且优美。返回搜狐,查看更多
责任编辑: