技能提升之路:探索算法世界(一)

340 阅读7分钟

前言

作为一名测试工程师,想要提高自己的编程能力,不像开发一样具备先天条件,他们可以通过写业务代码来逐渐提升,而一个小团队的测试工程师更多的工作还是在功能测试,没有那么多的机会去写代码,此时我们想要提高编程能力,就可以通过刷题来逐渐提升。刷算法题作为提升编程能力和解决实际问题的有效手段,受到越来越多程序员和学生的青睐。通过刷算法题,我们可以不断锻炼自己的逻辑思维能力、编程实现能力以及解决问题的技巧,为日后的实际工作和学习打下坚实的基础。

实践

题目一

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

解题思路:

  1. 暴力法:最容易想到的方法是使用两层循环遍历数组中的每一个元素,并查找是否存在另一个元素与之相加等于目标值。
  2. 哈希表:通过空间换时间,我们可以利用哈希表来降低时间复杂度。遍历数组过程中,可以将每个元素的值和索引存储在哈希表中。在存储过程中,我们可以同时检查当前元素的补数(target-nums[i])是否已经在哈希表中,如果是则直接返回结果。

实现过程:

暴力法比较简单,这里主要用哈希表来实现

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dic = {}
        for index, num in enumerate(nums):
            temp = target - num
            if temp in dic:
                return [dic[temp], index]
            dic[num] = index
        return [] 

我们对这段代码进行讲解:

  1. 首先,创建一个空的字典 dic,用于存储元素值和对应的索引。
  2. 使用 enumerate 函数遍历数组 nums,同时获取元素的索引和值。
  3. 对于每个元素,计算其与目标值的差值 temp
  4. 在字典 dic 中查找是否存在 temp,如果存在,则说明找到了符合条件的两个整数,直接返回它们的索引。
  5. 如果字典中不存在 temp,则将当前元素的值和索引存入字典。
  6. 如果遍历完数组后仍未找到符合条件的结果,则返回一个空列表。

需要注意的是,代码中使用了Python特有的语法和函数,如列表推导式、字典的键值对操作和enumerate函数。这些都是Python简洁和高效的特性,方便了代码的编写和阅读。

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组中的元素数量。在遍历数组的过程中,对于每一个元素,我们可以在哈希表中以 O(1) 的时间复杂度查找其补数。
  • 空间复杂度:O(n),其中 n 是数组中的元素数量。哈希表中存储了 n 个元素的值和索引。

题目二

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。字母异位词指字母相同,但排列不同的字符串。

解题思路:

1、创建一个空的哈希表 groups,用于存储分组后的结果。键为排序后的字符串(即字母相同且排列相同的字符串),值为属于该分组的字符串列表。

2、遍历字符串数组 strs 中的每一个字符串:

  • 将当前字符串 s 转换成排序后的字符串 key
  • 如果 key 已经存在于哈希表 groups 中,则将当前字符串 s 加入到对应的分组中。
  • 如果 key 不存在于哈希表 groups 中,则创建一个新的分组,并将当前字符串 s 加入到该分组中。

3、返回哈希表 groups 中的所有值(分组)作为结果。

实现过程:

import collections
​
class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        groups = collections.defaultdict(list)
        for s in strs:
            key = "".join(sorted(s))
            groups[key].append(s) 
        
        return list(groups.values())
​
solution = Solution()
solution.groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])  # [["bat"],["nat","tan"],["ate","eat","tea"]]

我们对这段代码进行讲解:

  1. 导入了 collections 模块,用于使用 defaultdict 来创建默认值为列表的字典。

  2. 定义了一个名为 Solution 的类,其中包含一个方法 groupAnagrams,用于实现字母异位词的分组。

  3. 方法 groupAnagrams 的参数包括 self 和 strs,其中 self 代表类的实例本身,而 strs 是一个字符串列表。

  4. 创建了一个默认值为列表的字典 groups,用于存储分组后的结果。

  5. 使用 for 循环遍历输入的字符串列表 strs 中的每一个字符串:

    • 将当前字符串 str 排序后连接成一个新的字符串 key。
    • 将原始的字符串 str 加入到对应 key 的分组中。
  6. 最后,返回字典 groups 的所有值(分组)作为结果列表。

复杂度分析:

  • 时间复杂度:O(n * k * log(k)),其中 n 是字符串数组 strs 的长度,k 是字符串的平均长度。对于每个字符串,我们需要花费 O(k * log(k)) 的时间进行排序。
  • 空间复杂度:O(n * k),需要额外的哈希表来存储分组后的结果。

题目三

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

解题思路:

  1. 首先,我们可以将数组中的所有元素存入一个集合(set)中,以便快速地进行查找操作。
  2. 接下来,我们遍历数组中的每一个元素 num,并检查是否存在比 num 小 1 的数字。如果不存在,则说明 num 是一个连续序列的开始。
  3. 对于每个连续序列的开始数字,我们通过不断增加当前数字的值来查找连续序列的长度。具体做法是,我们从该数字开始递增,直到找不到比当前数字大 1 的数字为止。
  4. 在查找过程中,我们记录每个连续序列的长度,并更新最大长度。最终,返回最大长度作为结果。

实现过程:

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        num_set = set(nums)
        max_len = 0
​
        for num in num_set:
            if num - 1 not in num_set:
                current_num = num
                current_len = 1
​
                while current_num + 1 in num_set:
                    current_num += 1
                    current_len += 1
                max_len = max(max_len, current_len)
​
        return max_len
​
solution = Solution()
solution.longestConsecutive([100,4,200,1,3,2]) # 4

我们对这段代码进行讲解:

  1. 首先,将输入的整数数组 nums 转换为一个集合 num_set。这样做可以提高查找操作的效率。

  2. 初始化最大长度 max_len 为 0。

  3. 对于集合 num_set 中的每个元素 num 进行遍历:

    • 如果 num - 1 不在 num_set 中,说明 num 是一个连续序列的开始。
    • 初始化当前数字和当前长度为 num 和 1。
    • 在循环中,通过递增当前数字的值,并判断递增后的数字是否存在于 num_set 中,来查找连续序列的长度。
    • 当找不到递增后的数字时,更新最大长度 max_len
  4. 最后,返回最大长度作为结果。

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组的长度。在遍历数组的过程中,我们对每个数字只进行了一次查找操作,并且查找操作的时间复杂度是 O(1)。
  • 空间复杂度:O(n),需要额外的空间来存储数字集合。

最后

当我们面对算法问题时,每一次解决都是一次成长。通过不断地思考、学习和实践,我们不仅提高了解决问题的能力,还培养了逻辑思维和分析技能。算法不仅仅是解决问题的工具,更是一种锻炼思维的方式。正如迈克尔·乔丹所说:“技术可以教,激情可以训练,但韧性却无法取代。”在刷题的过程中,我们不仅在不断提高自己的技术水平,更在锤炼自己的意志力和毅力。希望笔者可以坚持✊。