献芹奏曝-Python面试题-算法-数组篇

     上一篇:献芹奏曝-Python面试题 

      开篇的话:本文目的是收集和归纳力扣上的算法题,希望用python语言,竭我所能做到思路最清奇、代码最简洁、方法最广泛、性能最高效,了解常见题目,找到最利于记忆的答案,更加从容的应对面试。希望广思集益,共同进步。

 

数组篇

  1. 26. 删除有序数组中的重复项(难度系数✯)

    class Solution:
        def removeDuplicates(self, nums: List[int]) -> int:
            current_item = None
            for index,item in enumerate(nums[:]):
                if current_item == item:
                    nums.remove(item)
                current_item = item
            return len(nums)
    方法一

    运行结果:1:耗时超过13%。2:内存超过62% 

    知识点/技巧: 数组有序,当前元素和下一个比较,相同就 remove

    class Solution:
        def removeDuplicates(self, nums: List[int]) -> int:
            for i in range(len(nums) - 1, 0, -1):
                if nums[i] == nums[i - 1]:
                    del nums[i]
            return len(nums)
    方法二、降序删除

    运行结果:1:耗时超过47%。2:内存超过17% 

    知识点/技巧: 数组有序,倒叙循环,当前元素和前一个比较,相同就 del

    class Solution:
        def removeDuplicates(self, nums: List[int]) -> int:
            """
            利用双指针,因为是有序的,鸠占鹊巢
            """   
            slow = 0
            fast = 0
            while fast < len(nums):
                if nums[slow] != nums[fast]:
                    slow += 1
                    nums[slow] = nums[fast]
                fast += 1
            return slow + 1
    方法三

    运行结果:1:耗时超过62%。2:内存超过46% 

    知识点/技巧: 通过双指针,“鸠占鹊巢”

  2. 122. 买卖股票的最佳时机 II(难度系数✯)

    class Solution:
        def maxProfit(self, prices: List[int]) -> int:
            # 一言以蔽之,如果明天比今天股价高,就买
            is_have = False # 当前是否拥有股票
            profit = 0 # 当前利润
            if len(prices)<2:
                return profit
            for i in range(0,len(prices)):
                if is_have:
                        # 如果手上还有股票,就抛
                        profit += prices[i] - prices[i-1]
                        is_have = False
                if i+1<len(prices):
                    if prices[i+1]>prices[i]:
                        # 如果明天比今天股价高,就买。
                        is_have = True
    
            return profit
    方法一

    运行结果:1:耗时超过80%。2:内存超过33% 。3:思路奇特

    知识点/技巧: 一言以蔽之,手上有股票就卖;明天比今天股价高,就买。

  3. 189. 轮转数组(难度系数✯)

    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            if nums:
                if nums:
                    k = k%len(nums)
                right = nums[:-k:]
                left = nums[-k::]
                nums.clear()
                nums.extend(left)
                nums.extend(right)
    方法一

    运行结果:1:耗时超过92%。2:内存超过18%

    知识点/技巧: 先切片,再拼接 

    import copy
    from typing import List
    
    
    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            if nums:
                re_time = k % len(nums)
                len_nums = len(nums)
                if re_time > len_nums / 2:
                    re_time = len_nums - re_time
                    # 删除前面的元素往后面添加
                    for i in range(re_time):
                        nums.append(nums.pop(0))
                else:
                    # 删除后面的元素往前面添加
                    for i in range(re_time):
                        nums.insert(0, nums.pop(-1))
    一次失败的尝试

    运行结果:直接超时

    经验教训: 列表增删操作非常耗时

  4. 217. 存在重复元素(难度系数✯)

    class Solution:
        def containsDuplicate(self, nums: List[int]) -> bool:
            return len(set(nums))!=len(nums)
    方法一

    运行结果:1:耗时超过40%。2:内存超过33%。3:代码简洁

    知识点/技巧: 利用set去重,比较长度

    class Solution:
        def containsDuplicate(self, nums: List[int]) -> bool:
            dict_resut = {}
            for item in nums:
                if dict_resut.get(item):
                    return True
                else:
                    dict_resut[item]=1
            return False
    方法二

    运行结果:1:耗时超过76%。2:内存超过30%。

    知识点/技巧: 利用字典记录字母出现次数

  5. 1. 两数之和(难度系数✯)

    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            for index,item in enumerate(nums):
                for i in range(index+1,len(nums)):
                    if item + nums[i] == target:
                        return [index,i]
    方法一

    运行结果:1:耗时超过36%。2:内存超过68%。3:虽慢但对

    知识点/技巧: 遍历方法

    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            for index,item in enumerate(nums):
                result = target - item
                for i in range(index+1,len(nums)):
                    if nums[i] == result:
                        return [index,i]
    方法二

    运行结果:1:耗时超过36%。2:内存超过65%。3:虽然没有减少时间复杂度,但是减少了求和次数

    知识点/技巧:在方法一的基础上减少了求和运算,但是时间复杂度仍是O(n*n)

    class Solution:
        def twoSum(self, nums: List[int], target: int) -> List[int]:
            dict_res = {}
            for index,item in enumerate(nums):
                result=target-item
                if dict_res.get(result) != None:
                    return [dict_res.get(result),index]
                dict_res[item]=index
    方法三

    运行结果:1:耗时超过58%。2:内存超过41%。3:利用哈希表

    知识点/技巧: 哈希表作为读取和写入都很快的数据结构,常常用来实现空间换时间的效果。

  6. 167. 两数之和 II - 输入有序数组(难度系数✯)

    class Solution:
        import bisect
        def twoSum(self, numbers: List[int], target: int) -> List[int]:
            for index,item in enumerate(numbers):
                remain = target-item
                j = bisect.bisect_left(numbers,remain,index+1)
                if j != len(numbers) and numbers[j] == remain:
                    return [index+1,j+1]
    方法一

    运行结果:1:耗时超过67%。2:内存超过45%。3:利用二分查找法

    知识点/技巧: 利用升序数据的特性,通过二分查找方法来快速找到我们需要的值。

    class Solution:
        import bisect
        def twoSum(self, numbers: List[int], target: int) -> List[int]:
            i,j = 0, len(numbers)-1
            while i<j:
                current = numbers[i] + numbers[j]
                if current == target:
                    return [i+1,j+1]
                elif current<target:
                    i += 1
                else:
                    j -= 1
    方法二

    运行结果:1:耗时超过53%。2:内存超过40%。3:指针移动

    知识点/技巧: 使用指针移动技巧在时间复杂度和空间复杂度都更加优化的解法。

  7. 15. 三数之和(难度系数✯✯)

    class Solution:
        def threeSum(self, nums: List[int]) -> List[List[int]]:
            nums.sort()
            result_list = []
            for index, item in enumerate(nums):
                if index and item == nums[index-1]:
                    # 当前元素和上一元素相同
                    continue
                elif item>0:
                    # 点睛之笔
                    break
                target = -item
                i, j = index + 1, len(nums) - 1
                is_move_i = None
                while i < j:
                    current = nums[i] + nums[j]
                    if is_move_i == True:
                        if nums[i-1] == nums[i]:
                            i += 1
                            continue
                    elif is_move_i == False:
                        if nums[j+1] == nums[j]:
                            j -= 1
                            continue
                    if current == target:
                        result_list.append([item, nums[i], nums[j]])
                        i += 1
                        j -= 1
                        is_move_i = True
                    elif current < target: 
                        i += 1
                        is_move_i = True
                    else:
                        is_move_i = False
                        j -= 1
            return result_list
    方法一

    运行结果:1:耗时超过58%。2:内存超过50%。3:三数之和转换成两数和问题。

    知识点/技巧: 首先对数据进行排序,遍历的时候如果当前节点大于0,就无需继续遍历。

  8. 18. 四数之和(难度系数✯✯)

    class Solution:
        def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
            nums.sort()
            print(nums)
            result_list = []
            for i in range(0, len(nums) - 3):
                if i > 0 and nums[i - 1] == nums[i]:
                    continue
                if nums[i] + nums[len(nums) - 3] + nums[len(nums) - 2] + nums[len(nums) - 1] < target:
                    # 当前数+后面最大的三个值仍小于目标值,遍历下一位
                    continue
                if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:
                    # 当前数+后面最小的三个值仍大于目标值,退出
                    break
                for j in range(i + 1, len(nums) - 2):
                    m, n = j + 1, len(nums) - 1
                    if nums[i] + nums[j] + nums[len(nums) - 2] + nums[len(nums) - 1] < target:
                        continue
                    if j > i + 1 and nums[j - 1] == nums[j]:
                        continue
                    if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
                        break
                    is_move_m = None
    
                    while m < n:
                        current = nums[i] + nums[j] + nums[m] + nums[n]
                        if is_move_m == True:
                            if nums[m - 1] == nums[m]:
                                m += 1
                                continue
                        elif is_move_m == False:
                            if nums[n + 1] == nums[n]:
                                n -= 1
                                continue
                        if current == target:
                            result_list.append([nums[i], nums[j], nums[m], nums[n]])
                            m += 1
                            n -= 1
                            is_move_m = True
                        elif current < target:
                            m += 1
                            is_move_m = True
                        else:
                            is_move_m = False
                            n -= 1
            return result_list
    方法一

    运行结果:1:耗时超过82%。2:内存超过9%。

    知识点/技巧: 在处理三数之和的基础,暴力循环,循环时进行优化

  9. 36. 有效的数独(难度系数✯✯)

    class Solution:
        def get_dic(self):
            dic_result = {}
            for i in range(1, 10):
                key_1 = "0_%s" % i
                key_2 = "%s_0" % i
                dic_result.setdefault(key_1, [])
                dic_result.setdefault(key_2, [])
                if not i % 3:
                    key_3 = "3_%s" % i
                    key_6 = "6_%s" % i
                    key_9 = "9_%s" % i
                    dic_result.setdefault(key_3, [])
                    dic_result.setdefault(key_6, [])
                    dic_result.setdefault(key_9, [])
            return dic_result
    
        def isValidSudoku(self, board: List[List[str]]) -> bool:
            dic_result = self.get_dic()
            for raw_index, raw_item in enumerate(board):
                for col_index, col_item in enumerate(raw_item):
                    if col_item != ".":
                        dic_result[str(raw_index + 1) + "_0"].append(col_item)
                        dic_result["0_" + str(col_index + 1)].append(col_item)
                        key_sq_r = (raw_index // 3 + 1) * 3
                        key_sq_c = (col_index // 3 + 1) * 3
                        dic_result["%s_%s" % (key_sq_r, key_sq_c)].append(col_item)
            for value in dic_result.values():
                if len(set(value)) != len(value):
                    return False
            else:
                return True
    方法一

    运行结果:1:耗时超过88%。2:内存超过68%。

    知识点/技巧: 只要我的方法够暴力,问题就难不倒我

  10. 48. 旋转图像(难度系数✯✯✯)

    class Solution:
        def rotate(self, matrix: List[List[int]]) -> None:
            """
            Do not return anything, modify matrix in-place instead.
            """
            mid_line = len(matrix) // 2 if len(matrix) % 2 else len(matrix) // 2
            for i in range(mid_line):
                for j in range(len(matrix)):
                    matrix[i][j], matrix[len(matrix) - 1 - i][j] = matrix[len(matrix) - i - 1][j], matrix[i][j]
            for i in range(len(matrix)):
                for j in range(i, len(matrix)):
                    matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
           
    方法一

    运行结果:1:耗时超过29%。2:内存超过74%。

    知识点/技巧: 先水平翻转,再进行主对角线翻转

  11.  554. 砖墙(难度系数✯✯)

    class Solution:
        def leastBricks(self, wall) -> int:
            dict_sum = {}
            for row in wall:
                sum = 0
                for item in row[:len(row)-1]:
                    sum += item
                    dic_value = dict_sum.get(sum,0)
                    dic_value += 1
                    dict_sum[sum] = dic_value
            if not dict_sum:
                return len(wall)
            max_ = max(dict_sum.values())
            return len(wall) - max_
    View Code

    运行结果:1:耗时超过80%。2:内存超过11%。

    知识点/技巧: 每行累计求和找到墙缝

  12. 539. 最小时间差(难度系数✯)

    class Solution:
        def findMinDifference(self, timePoints: List[str]) -> int:
            # 如果长度大于24*60个 绝对会重复
            if len(timePoints)>24*60:
                return 0
            list_r = []
            for item in timePoints:
                hh,mm = item.split(":")
                list_r.append(int(hh)*60+int(mm))
            list_r.sort()
            result = 24*60
            for i,item in enumerate(list_r):
                if i==0:
                    # 首位判断,转一圈,绕过去
                    result = min( list_r[-1]-item,result-list_r[-1]+item)
                else:
                    result = min(result,item-list_r[i-1])
                if result == 0:
                    return result
            return result
    View Code

    运行结果:1:耗时超过90%。2:内存超过96%。

    知识点/技巧: 1:抽屉原理 判断极限 24*60。2:直接小时数乘60+分钟数,排序,最后再比较一下首尾就行。

posted @ 2022-03-06 17:43  逍遥小天狼  阅读(70)  评论(0编辑  收藏  举报