前端面试的作品示例_示例Swift代码面试问题-第1/3部分

前端面试的作品示例

As LeetCode extends its code challenge to May, it is a good opportunity for us to keep polishing up our coding skills. Besides, it is a helpful tool for us to prepare for iOS technical interviews.

随着LeetCode将其代码挑战扩展到May ,这对我们来说是一个很好的机会,可以继续提高我们的编码技能。 此外,它对于我们准备iOS技术面试也是一个有用的工具。

Why would coding practice help our interviews? In my iOS technical interview experience (entry to mid-level), only less than 20% of them are about iOS field knowledge, the rest 80% of them are coding questions that require practical skills. Furthermore, most of those coding questions may not be as related to your daily iOS development, instead, they are mainly focusing on Data Structures and Algorithms. It would be better to get some sense of them before interviews.

为什么编码实践会帮助我们的面试? 在我的iOS技术面试经验(入门级到中级水平)中,只有不到20%是关于iOS领域知识的,其余80%是需要实践技能的编码问题 。 此外,这些编码问题中的大多数可能与您的日常iOS开发无关,而是主要关注数据结构算法 。 面试前最好先了解一下它们。

Continuing on our April code challenge, I will publish another series of articles to talk through the challenge questions using Swift. In this May edition, instead of walking through all 30 questions, I intend to just select the questions that are more popular in interviews.

继续我们四月份的代码挑战,我将发表另一系列文章,以使用Swift讨论挑战问题。 在今年5月的这个版本中,我没有选择全部30个问题,而是打算选择在访谈中更受欢迎的问题。

For people who want to work on their own, feel free to utilize my Github repo, which includes a solution and unit tests for each coding question.

对于想独立工作的人,请随时使用我的Github存储库 ,其中包括解决方案和每个编码问题的单元测试。

In this article, we will discuss the following selected programming questions from May LeetCoding Challenge.

在本文中,我们将讨论May LeetCoding Challenge提出的以下一些编程问题。

  1. First Unique Character in a String (Solution)

    字符串中的第一个唯一字符 ( 解决方案 )

  2. Cousins in Binary Tree (Solution)

    表兄弟在二叉树中 ( 解决方案 )

  3. Flood Fill (Solution)

    洪水填充 ( 解决方案 )

  4. Remove K Digits (Solution)

    删除K位数字 ( 解决方案 )

  5. Implement Trie (Prefix Tree) (Solution)

    实现Trie(前缀树) ( 解决方案 )

  6. Maximum Sum Circular Subarray (Solution)

    最大和圆子数组 ( )

  7. Odd-Even Linked List (Solution)

    奇偶链接列表 ( 解决方案 )

字符串中的第一个唯一字符 (First Unique Character in a String)

Description: Given a string, find the first non-repeating character in it and return its index. If it doesn’t exist, return -1.

描述 :给定一个字符串,找到其中的第一个非重复字符并返回其索引。 如果不存在,则返回-1

Example 1input: "leetcode"output: 0Example 2input: "loveleetcode"output: 2

The solution we are targeting here is a linear time solution since we have to go over the entire string to know which one is unique in it. A straightforward method we can easily think of is having a Dictionary record letter frequency. Subsequently, iterate over the input again and return the index that has a letter frequency of 1.

我们这里要针对的解决方案是线性时间解决方案,因为我们必须遍历整个字符串才能知道哪个是唯一的。 我们可以轻松想到的一种简单的方法是使用字典记录字母频率。 随后,再次遍历输入,并返回字母频率为1的索引。

Let’s add some difficulty, say the interviewer wants you to come up a one-pass solution, what would you do?

让我们增加一些困难,比如说面试官希望您提出一种一次性解决方案,您会怎么做?

I propose a data structure that is similar to what we did in LRU, where we use a Dictionary and a Doubly Linked List to achieve constant-time moving the elements in the list.

我提出了一种数据结构,该结构类似于在LRU中所做的工作,在LRU中 ,我们使用了DictionaryDoubly Linked List来实现恒定时间地移动列表中的元素。

With both data structure set up, we iterate over the input string. When we find a letter that doesn’t present in our dictionary, we append it to the linked list. In contrast, if the letter already exists in the dictionary, we remove it from the list and mark its idx as -1. Afterward, when we see a letter with -1 as idx in the dictionary, we just skip it since it already has duplicates. Finally, we return the first node after the head as the first unique character. The solution is shown below.

设置了两种数据结构后,我们遍历输入字符串。 当我们发现字典中不存在的字母时, 会将附加到链接列表中。 相反,如果该字母已存在于字典中,则将其从列表中删除 ,并将其idx标记为-1 。 之后,当我们在字典中看到一个以-1作为idx的字母时,由于它已经有重复项,因此我们将其跳过。 最后,我们将head后面的第一个节点作为第一个唯一字符返回。 解决方案如下所示。

Time complexity: O(N). Both straightforward and optimized solutions have linear runtime. However, the straightforward solution is only better than 20% of Swift entries while the optimized one with a doubly-linked list is better than 90% of Swift entries. You can test the performance of your solution here.

时间复杂度: O(N) 。 简单和优化的解决方案都具有线性运行时间。 但是,直接的解决方案仅优于Swift条目的20% ,而经过优化的带有双向链接列表的解决方案优于Swift条目的90% 。 您可以在此处测试解决方案的性能。

表弟在二叉树 (Cousins in Binary Tree)

Description: In a binary tree, the root node is at depth 0, and children of each depth k node are at depth k + 1. Two nodes of a binary tree are cousins if they have the same depth, but have different parents.

描述 :在二叉树中,根节点在深度0处 ,每个深度k节点的子节点在深度k +1处 。 如果二叉树的两个节点具有相同的深度,但是具有不同的父级 ,则它们是表亲

We are given a binary tree with unique values and the values x and y of two different nodes in the tree. Return true if and only if the nodes corresponding to the values x and y are cousins.

我们给了一个具有唯一值的二叉树,以及树中两个不同节点的值xy 。 当且仅当与值xy对应的节点是表亲时,才返回true

Example 1    1
/ \
2 3
/
4
x = 4, y = 3Output: falseExample 2 1
/ \
2 3
\ \
4 5
x = 5, y = 4Output: false

I plan to traverse the entire tree and use a Set Array to backtrack each level. The indices of the array represent the level in the tree. In each level, there is a set corresponding to it, which contains all the tree nodes at that level.

我计划遍历整个树,并使用Set Array回溯每个级别。 数组的索引表示树中的级别。 在每个级别中,都有一个与之对应的集合,其中包含该级别的所有树节点。

Having the data structures set up, we can look up if the set at a certain level contains x and y after inserting a new node. The goal is to see whether x and y ever coexist in the same set. We can return true and end the process once the goal is fulfilled.

设置好数据结构后,我们可以在插入新节点后查询某个级别的集合是否包含xy 。 目的是查看xy是否在同一集合中共存。 一旦实现目标,我们就可以返回true并结束流程。

Besides, according to the problem definition, we have to ensure that x and y never have the same root. If they ever do, we return false and end the recursion. The logic is shown in the following solution.

此外,根据问题定义,我们必须确保xy永远不要具有相同的 。 如果他们这样做,我们将返回false并结束递归。 逻辑显示在以下解决方案中。

Time complexity: O(N) where N is the number of the nodes in the tree. The worst case is that x and y are at a very deep level so that we have to traverse the entire tree to determine if they are cousins. A side note that we use a Set here is because it has constant time lookup capability. Although Array has contains(_:) function, it takes linear time to execute the function.

时间复杂度: O(N) ,其中N是树中节点的数量。 最坏的情况是xy处于很深的水平,因此我们必须遍历整个树来确定它们是否是表亲。 我们在这里使用Set的一个侧面说明是因为它具有恒定的时间查找功能。 尽管Array具有contains(_ :)函数,但是执行该函数需要花费线性时间

洪水填充 (Flood Fill)

Description: An image is represented by a 2-D array of integers, each integer representing the pixel value of the image (from 0 to 65535).

Description(说明)图像由一个二维整数数组表示,每个整数代表图像的像素值(从0到65535)。

Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, “flood fill” the image.

给定一个代表泛洪填充的起始像素(行和列)的坐标(sr,sc) ,以及一个像素值newColor ,将图像“泛洪”。

To perform a “flood fill”, consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor. Return the modified image.

要执行“泛洪填充”,请考虑起始像素,再加上四向连接到与起始像素颜色相同的起始像素的所有像素,再加上任意四向连接到这些像素(也具有相同颜色的像素)的像素起始像素),依此类推。 用newColor替换所有上述像素的颜色 。 返回修改后的图像。

ExampleInput: image = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
]sr = 1, sc = 1, newColor = 2Output: [
[2, 2, 2],
[2, 2, 0],
[2, 0, 1]
]

In the example, the painting starts at (1, 1), where we can note the old color as 1. Going 4-directionally, wherever there is a 1 element, it is replaced by 2. On the other hand, we skip all other non-1 elements.

在示例中,绘画从(1,1)开始 ,在这里我们可以将旧颜色记1 。 进行4方向转换,只要有1个元素,就将其替换为2 。 另一方面,我们跳过所有其他非1元素。

A Depth-First Search(DFS) method is suitable for this question. Traversing 4-directionally from the given starting point, we paint the new color whenever and wherever the old color is found. The terminating condition is when there is no old color element found in 4-direction. See the following solution.

深度优先搜索 (DFS)方法适用于此问题。 从给定的起点开始四向遍历,无论何时何地,只要找到旧颜色,我们都会绘制新颜色。 终止条件是在4方向上找不到旧的颜色元素时。 请参阅以下解决方案。

Time complexity: O(N) where N is the pixels in the image. In the worst case, we may need to repaint all the pixels.

时间复杂度: O(N) ,其中N是图像中的像素。 在最坏的情况下,我们可能需要重新绘制所有像素。

删除K位数字 (Remove K Digits)

Description: Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible.

描述 :给定一个以字符串表示的非负整数num ,请从数字中删除k个数字,以使新数字尽可能最小。

Example 1num: "1432219", k: 3output: "1219"Example 2num: "10200", k: 1output: "200"Example 3num: "10", k: 2output: "0"

Let’s get started with a simple example, if you are given five digits — 1, 2, 3, 4, 5, what order can make the number smallest? The answer is 12345. The key feature we can observe from it is its digits are in ascending order, which puts the smaller numbers ahead of the larger numbers.

让我们开始用一个简单的例子,如果你给出五个数字- 1,2,3,4,5,什么样的顺序可以使数最小? 答案是12345 。 我们可以从中观察到的主要特征是其数字按升序排列,这使较小的数字位于较大的数字之前。

Knowing the fact that placing digits in ascending order makes it smaller, we are ready to work on the solution. First of all, create an Array(used as Stack) to keep track of the digits iterated. When we move on to a new digit, we always compare it with the last element in the array. If the new digit is smaller than the array.last, we remove last in the array and decrement k by 1 to keep the output as close to ascending order as possible. The comparison is a repeated process until we can’t find any array.last that is larger than the new digit or k is equal to 0.

知道将数字按升序排列会使其变小的事实,我们已准备好解决该问题。 首先,创建一个Array (用作Stack )以跟踪迭代的数字。 当我们移动到新的数字时,我们总是将其与数组中的最后一个元素进行比较。 如果新数字小于array.last ,则删除数组中的last ,并将k1以使输出尽可能接近升序。 比较是一个重复的过程,直到找不到任何大于新数字或k等于0的 array.last为止。

Ideally, the k is consumed in the above process. Nonetheless, if it isn’t, we need to handle it separately. The above process already makes the array in the most achievable ascending order. There’s not much we can do toward that direction. Alternatively, we can start removing elements from the back of the array, which can make an ascending order number smaller.

理想地,在上述过程中消耗k 。 但是,如果不是,我们需要单独处理。 上面的过程已经使阵列以最可实现的升序排列。 我们朝这个方向没有什么可以做的。 或者,我们可以开始从数组的后面删除元素,这可以使升序数变小。

Finally, after we are done with removing elements (k = 0), we have to take care of the leading 0s. Since a valid number should not have leading 0s, we have to remove all of them. Cleaning them up, we are ready to return our output.

最后,在完成删除元素( k = 0 )之后,我们必须注意前导0 s。 由于有效数字不应以0开头,因此我们必须将其全部删除。 清理它们,我们准备返回我们的输出。

Time complexity: O(N+k). In the first while loop, we have to iterate over the entire input string. Whenever we find a number that meets our removal condition, we switch to another while loop inside and start removing array elements. The inner while loop will at most run k times while the outer one will be executed N times. Besides, the other two while loops are presumed to be less than N. Therefore, the runtime of the entire solution is O(N+k).

时间复杂度: O(N + k) 。 在第一个while循环中,我们必须遍历整个输入字符串。 每当我们找到一个满足删除条件的数字时,我们就会在内部切换到另一个while循环并开始删除数组元素。 内部的while循环最多会运行k次,而外部的while循环将执行N次。 此外,其他两个while循环假定小于N。 因此,整个解决方案的运行时间为O(N + k)

实施Trie(前缀树) (Implement Trie (Prefix Tree))

Following the protocol and implement a trie with insert, search, and startWith methods.

遵循该协议,并使用insertsearchstartWith方法实现trie。

Trie is an efficient information retrieval data structure. It is widely applied in search engines where it helps improve the search complexity to an optimal limit.

Trie是一种有效的信息检索数据结构。 它广泛应用于搜索引擎,可帮助将搜索复杂度提高到最佳极限。

Trie is a kind of tree. However, unlike a binary tree that each node has at most two child nodes, a node in Trie can have as many child nodes as possible. To implement this feature, a TrieNode will look like the following:

特里是一种树。 但是,与每个节点最多具有两个子节点的二叉树不同,Trie中的一个节点可以具有尽可能多的子节点。 要实现此功能, TrieNode将如下所示:

We are using Character as the key in this Trie data structure.

我们正在使用Character作为此Trie数据结构中的键。

Let’s start with the insertion operation. When we insert a new key to the Trie, we search from the root to see if there is a link to one of its children that matches the first character of the key. If the link exists, we move down the tree and move to the next character. Then repeat the link searching process until all key characters have been searched in the Trie or there is no link found. If there is no link found, we create a new node using the current key character and link it with the parent’s node. Again, this process repeats until all key characters are processed. At the end of the process, we add an end node as its child.

让我们从插入操作开始。 当我们向Trie插入新密钥时,我们从根目录开始搜索以查看是否存在指向与该密钥的第一个字符匹配的子项的链接。 如果链接存在,我们将向下移动树并移至下一个字符。 然后重复链接搜索过程,直到在Trie中搜索了所有关键字符或找不到链接。 如果没有找到链接,我们将使用当前的关键字符创建一个新节点,并将其与父节点链接。 同样,重复此过程,直到处理完所有关键字符为止。 在该过程的最后,我们添加一个结束节点作为其子节点

The search operation is similar to what we did in insertion. Starting from the root node, we keep on finding if there is a link from the parent’s node to its child node that matches the current key character. If there exists, we move down the tree and move to the next character to continue searching. The process repeats until there is no link found or the key has been processed entirely. If the key has been fully processed, we want to check if there is an end node among the children of the current node. We can only determine the key exists(true) in the Trie if the end node is attached. Besides, during the search process, whenever the link is not found, we can break the process and return false as the key doesn’t exist in the Trie.

搜索操作类似于我们在插入操作中所做的操作。 从根节点开始,我们继续查找父节点到其子节点是否存在与当前关键字符匹配的链接。 如果存在,我们将向下移动树并移至下一个字符以继续搜索。 重复该过程,直到找不到链接或密钥已被完全处理。 如果密钥已被完全处理,我们要检查当前节点的子节点中是否有一个末端节点。 如果连接了末端节点,我们只能确定Trie中的键存在(true) 。 此外,在搜索过程中,只要没有找到的链接,我们可以打破的过程和返回false作为关键不在特里存在。

Lastly, if you understand how the search works, the prefix operation is a simple version of the search function. To check whether a prefix exists, we only need to relentlessly find links until the input key is fully processed. Similar to the search operation, whenever a link is not found can be considered a negative result. Conversely, if all the links exist in the Trie, we can return a positive result.

最后,如果您了解搜索的工作原理,则前缀操作是搜索功能的简单版本。 要检查前缀是否存在,我们只需要不懈地寻找链接,直到输入键被完全处理为止。 与搜索操作类似,每当找到链接时,都可以视为否定结果。 相反,如果所有链接都存在于Trie中,则我们可以返回肯定结果。

Time complexity: O(M) where M is the key length. The runtimes of the three operations are all decided by the key length. It is pretty obvious for the insertion. Apart from it, the search and prefix operation is a bit different. O(M) happens as the worst case when the key exists in the Trie. In such a case, we have to at least move down M times to process the entire key.

时间复杂度: O(M)其中M是密钥长度。 这三个操作的运行时间都由密钥长度决定。 对于插入来说是很明显的。 除此之外, 搜索前缀操作略有不同。 当密钥存在于Trie中时, O(M)作为最坏的情况发生。 在这种情况下,我们必须至少向下移动M次才能处理整个密钥。

Here we conclude our first 5 of the 15 questions selected from May LeetCoding Challenge. For more resources of it, you can find them in my Github. Feel free to contribute to my Github or to send me emails if there’s something you’d like to discuss.

在这里,我们总结了从May LeetCoding Challenge选出的15个问题中的前5 问题。 有关更多资源,您可以在我的Github中找到它们。 如果您想讨论什么,请随时为我的Github贡献力量或给我发送电子邮件。

翻译自: https://medium.com/swlh/top-15-swift-code-interview-questions-from-may-code-challenge-part-1-3-65c3dc11851b

前端面试的作品示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值