《算法通关之路》chapter19解题技巧和面试技巧

《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。

1 看限制条件

1.1数据规模

有的题目数据规模较小,那么暴力法就可行;如果暴力法不行,那么再稍微加一个诸如缓存和剪枝的优化一般可以通过。

根据题目所给的数据规模,就大概锁定了能够选择的算法。
1 0 6 10^{6} 106可接受的复杂度O(nlogn)
1 0 7 10^{7} 107可接受的复杂度O(n)

转化为全零矩阵的最少反转次数

力扣第1284题
给你一个 m x n 的二进制矩阵 mat。每一步,你可以选择一个单元格并将它反转(反转表示 0 变 1 ,1 变 0 )。如果存在和它相邻的单元格,那么这些相邻的单元格也会被反转。相邻的两个单元格共享同一条边。

请你返回将矩阵 mat 转化为全零矩阵的最少反转次数,如果无法转化为全零矩阵,请返回 -1 。

二进制矩阵 的每一个格子要么是 0 要么是 1 。

全零矩阵 是所有格子都为 0 的矩阵。

1 <= m <= 3
1 <= n <= 3

'''
方法一:广度优先遍历(降维)时间复杂度:O(2^{mn})
空间复杂度:O(2^{mn})
'''class Solution:def minFlips(self, mat: list[list[int]]) -> int:# 放到flip函数外部可以减少计算mapper = {'0': '1', '1': '0'}def flip(state: list[str], i: int) -> None:state[i] = mapper[state[i]]if i % n != 0:state[i - 1] = mapper[state[i - 1]]if i % n < n - 1:state[i + 1] = mapper[state[i + 1]]if i >= n:state[i - n] = mapper[state[i - n]]if i < (m - 1) * n:state[i + n] = mapper[state[i + n]]m, n = len(mat), len(mat[0])target = '0' * (m * n)cur = ''.join(str(cell) for row in mat for cell in row)queue = [cur]visited = set()steps = 0while len(queue) > 0:for _ in range(len(queue)):cur = queue.pop(0)if cur == target:return stepsif cur in visited:continuevisited.add(cur)for i in range(len(cur)):s = list(cur)flip(s, i)queue.append(''.join(s))steps += 1return -1mat = [[0,0],[0,1]]
solu = Solution()
solu.minFlips(mat)
3

1.2 复杂度

题目要求时间复杂度是对数复杂度,就很容易想到二分查找。
题目要求常数的空间复杂度,就很容易想到原地算法。
题目中出现有序,应该联想到双指针、二分法等有序序列算法。
题目中出现连续子数组或连续子串,我们应该联想到滑动窗口。

矩阵置零

力扣第73题
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

'''
方法一:原地算法时间复杂度:O(mn)
空间复杂度:O(1)
'''class Solution:def setZeroes(self, matrix: list[list[int]]) -> None:C = len(matrix[0])R = len(matrix)def setRowZeros(matrix: list[list[int]], i: int) -> None:matrix[i] = [0] * Cdef setColZeros(matrix: list[list[int]], j: int) -> None:for i in range(R):matrix[i][j] = 0isCol = False # 如果不使用一个变量来存第一行或者第一列,最后矩阵会都变为0for i in range(R):if matrix[i][0] == 0:isCol = Truefor j in range(1, C):if matrix[i][j] == 0:matrix[i][0] = 0matrix[0][j] = 0for j in range(1, C): # 第一列存着行的变换if matrix[0][j] == 0:setColZeros(matrix, j)for i in range(R):if matrix[i][0] == 0:setRowZeros(matrix, i)if isCol:setColZeros(matrix, 0)matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
solu = Solution()
solu.setZeroes(matrix)
print(matrix)
[[0, 0, 0, 0], [0, 4, 5, 0], [0, 3, 1, 0]]

2 预处理

提前将计算结果存起来,在实际的计算过程中直接使用,从而节省计算资源。虽然打表是空间换时间,但是其空间并不随着数据规模增大而增大,很多情况下都是值得的。

顺次数

力扣第1291题
我们定义「顺次数」为:每一位上的数字都比前一位上的数字大 1 的整数。

请你返回由 [low, high] 范围内所有顺次数组成的 有序 列表(从小到大排序)。

10 <= low <= high <= 10^9

'''
方法一:打表时间复杂度:O(1)
空间复杂度:O(1)
'''class Solution:def sequentialDigits(self, low: int, high: int) -> list[int]:numbers = '123456789'ins = []n = len(numbers)for i in range(1, n): # i控制长度for j in range(n - i): # j控制位置ins.append(int(numbers[j : i + j + 1]))return [x for x in ins if x >= low and x <= high]low, high = 1000, 13000
solu = Solution()
solu.sequentialDigits(low, high)
[1234, 2345, 3456, 4567, 5678, 6789, 12345]
'''
方法二:打表 + 二分查找时间复杂度:O(1)
空间复杂度:O(1)
'''import bisectclass Solution:def sequentialDigits(self, low: int, high: int) -> list[int]:numbers = '123456789'ins = []n = len(numbers)for i in range(1, n): # i控制长度for j in range(n - i): # j控制位置ins.append(int(numbers[j : i + j + 1]))return ins[bisect.bisect_left(ins, low) : bisect.bisect(ins, high)]low, high = 1000, 13000
solu = Solution()
solu.sequentialDigits(low, high)
[1234, 2345, 3456, 4567, 5678, 6789, 12345]
'''
方法三:最朴实的打表时间复杂度:O(1)
空间复杂度:O(1)
'''import bisectclass Solution:def sequentialDigits(self, low: int, high: int) -> list[int]:ins = [12, 23, 34, 45, 56, 67, 78, 89, 123, 234, 345, 456, 567, 678, 789, 1234, 2345, 3456, 4567, 5678, 6789, 12345, 23456, 34567, 45678, 56789, 123456, 234567, 345678, 456789, 1234567, 2345678, 3456789, 12345678, 23456789, 123456789]return ins[bisect.bisect_left(ins, low) : bisect.bisect(ins, high)]low, high = 1000, 13000
solu = Solution()
solu.sequentialDigits(low, high)
[1234, 2345, 3456, 4567, 5678, 6789, 12345]

单词接龙

力扣第127题
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> … -> sk:

每一对相邻的单词只差一个字母。
对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
sk == endWord
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

'''
方法一:暴力BFS(超时)时间复杂度:O(m^2*n)
空间复杂度:O(n)
'''class Solution:def ladderLength(self, beginWord: str, endWord: str, wordList: list[str]) -> int:queue = [beginWord]visited = set()steps = 1L = len(beginWord)while len(queue) > 0:for _ in range(len(queue)):cur = queue.pop(0)if cur in visited:continuevisited.add(cur)if cur == endWord:return stepsfor i in range(L):for j in range(26):s = list(cur)s[i] = chr(ord('a') + j) # ord()转换ASCII码,chr转换为字符for word in wordList:if word == ''.join(s):queue.append(word)steps += 1return 0beginWord, endWord, wordList = "hit", "cog", ["hot","dot","dog","lot","log","cog"]
solu = Solution()
solu.ladderLength(beginWord, endWord, wordList)
5
'''
方法二:预处理 + BFS (空间换时间)时间复杂度:O(m*n)
空间复杂度:O(m*n)
'''from collections import defaultdictclass Solution:def ladderLength(self, beginWord: str, endWord: str, wordList: list[str]) -> int:queue = [beginWord]visited = set()steps = 1L = len(beginWord)n = len(wordList)wizards = defaultdict(list)for i in range(n):word = wordList[i]for j in range(L):wizards[word[:j] + '*' + word[j + 1 : ]].append(word)print(wizards)while len(queue) > 0:for _ in range(len(queue)):cur = queue.pop(0)if cur in visited:continuevisited.add(cur)if cur == endWord:return stepsfor i in range(L):for word in wizards.get(cur[:i] + '*' + cur[i + 1 :], []):queue.append(word)steps += 1return 0beginWord, endWord, wordList = "hit", "cog", ["hot","dot","dog","lot","log","cog"]
solu = Solution()
solu.ladderLength(beginWord, endWord, wordList)
5

3 不要忽视暴力法

统计全为 1 的正方形子矩阵

力扣第1277题
给你一个 m * n 的矩阵,矩阵中的元素不是 0 就是 1,请你统计并返回其中完全由 1 组成的 正方形 子矩阵的个数。

'''
方法一:暴力法(超时)时间复杂度:O(m*n*min(m,n))
空间复杂度:O(1)
'''class Solution:def countSquares(self, matrix: list[list[int]]) -> int:num_rows, num_cols = len(matrix), len(matrix[0])min_side_length = min(num_rows, num_cols)def is_all_ones(matrix):for row in matrix:for element in row:if element != 1:return Falsereturn Truecnt = 0for side_length in range(1, min_side_length + 1):for i in range(num_rows - side_length + 1):for j in range(num_cols - side_length + 1):if is_all_ones([row[j : j + side_length] for row in matrix[i : i + side_length]]): # 遍历二维list中所有边长为side_length的正方形cnt += 1return cntmatrix = [[0,1,1,1],[1,1,1,1],[0,1,1,1]
]
solu = Solution()
solu.countSquares(matrix)
15
'''
方法二:动态规划时间复杂度:O(m*n)
空间复杂度:O(m*n)
'''class Solution:def countSquares(self, matrix: list[list[int]]) -> int:num_rows, num_cols = len(matrix), len(matrix[0])cnt = 0# dp[i][j]表示以顶点i,j为右下角所能构成的最大正方形边长dp = [[0] * (num_cols + 1) for _ in range(num_rows + 1)]for i in range(1, num_rows + 1):for j in range(1, num_cols + 1):if matrix[i - 1][j - 1] == 1:dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1cnt += dp[i][j]return cntmatrix = [[0,1,1,1],[1,1,1,1],[0,1,1,1]
]
solu = Solution()
solu.countSquares(matrix)
15

子串的最大出现次数

力扣第1297题
给你一个字符串 s ,请你返回满足以下条件且出现次数最大的 任意 子串的出现次数:

子串中不同字母的数目必须小于等于 maxLetters 。
子串的长度必须大于等于 minSize 且小于等于 maxSize 。

'''
方法一:暴力法时间复杂度:O((26^2)*n)
空间复杂度:O((26^2)*n)
'''class Solution:def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:counter = {}for i in range(0, len(s) - minSize + 1): # 记住这种写法for length in range(minSize, maxSize + 1):if i + length > len(s):breaksub = s[i : i + length]if len(set(sub)) <= maxLetters: # 用set统计不同字符数目counter[sub] = counter.get(sub, 0) + 1return max(counter.values()) if counter else 0s, maxLetters, minSize, maxSize = "aababcaab", 2, 3, 4
solu = Solution()
solu.maxFreq(s, maxLetters, minSize, maxSize)
2
'''
方法二:暴力法剪枝(只统计长度为minSize的子串即可)时间复杂度:O(26*n)
空间复杂度:O(26*n)
'''class Solution:def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:counter = {}for i in range(0, len(s) - minSize + 1):sub = s[i : i + minSize]if len(set(sub)) <= maxLetters:counter[sub] = counter.get(sub, 0) + 1return max(counter.values()) if counter else 0s, maxLetters, minSize, maxSize = "aababcaab", 2, 3, 4
solu = Solution()
solu.maxFreq(s, maxLetters, minSize, maxSize)
2

4 降维与状态压缩

# 判断一个字符串中的字符是否全部唯一(状态压缩)def isUnique(s: str) -> bool:seen = 0 # 相当于set()for c in s:if seen & 1 << ord(c) - ord('a') != 0: # 相当于判断c是否在set中return Falseseen |= 1 << ord(c) - ord('a') # 相当于将c加入setreturn TrueisUnique('absxssxsxsxsxsx')
False

生命游戏

力扣第289题
根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。

'''
方法一:常规方法时间复杂度:O(mn)
空间复杂度:O(mn)
'''import copyclass Solution:def gameOfLife(self, board: list[list[int]]) -> None:"""Do not return anything, modify board in-place instead."""m, n = len(board), len(board[0])old = copy.deepcopy(board)def cntLiveCell(i: int, j: int) -> int:cnt = 0directions = [(0, 1),(0, -1),(-1, 0),(1, 0),(1, 1),(1, -1),(-1, 1),(-1, -1)]for (dx, dy) in directions:if i + dx >= 0 and i + dx < m and j + dy >= 0 and j + dy < n:cnt += old[i + dx][j + dy]return cntfor i in range(m):for j in range(n):cnt = cntLiveCell(i, j)if old[i][j] == 0 and cnt == 3:board[i][j] = 1if old[i][j] == 1 and (cnt < 2 or cnt > 3):board[i][j] = 0board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
solu = Solution()
solu.gameOfLife(board)
print(board)
[[0, 0, 0], [1, 0, 1], [0, 1, 1], [0, 1, 0]]
'''
方法二:状态压缩(将这个细胞中有多少活细胞这个信息存储到高位)时间复杂度:O(mn)
空间复杂度:O(1)
'''class Solution:def gameOfLife(self, board: list[list[int]]) -> None:"""Do not return anything, modify board in-place instead."""m, n = len(board), len(board[0])def cntLiveCell(i: int, j: int) -> int:cnt = 0directions = [(0, 1),(0, -1),(-1, 0),(1, 0),(1, 1),(1, -1),(-1, 1),(-1, -1)]for (dx, dy) in directions:if i + dx >= 0 and i + dx < m and j + dy >= 0 and j + dy < n:cnt += board[i + dx][j + dy] & 1return cntfor i in range(m):for j in range(n):cnt = cntLiveCell(i, j)board[i][j] |= cnt << 1for i in range(m):for j in range(n):cell = board[i][j] & 1cnt = board[i][j] >> 1if cell == 0 and cnt == 3:board[i][j] = 1elif cell == 1 and (cnt > 3 or cnt < 2):board[i][j] = 0else:board[i][j] = cellboard = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
solu = Solution()
solu.gameOfLife(board)
print(board)
[[0, 0, 0], [1, 0, 1], [0, 1, 1], [0, 1, 0]]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云安全之访问控制的常见攻击及防御

访问控制攻击概述 访问控制漏洞即应用程序允许攻击者执行或者访问某种攻击者不具备相应权限的功能或资源。 常见的访问控制可以分为垂直访问控制、水平访问控制及多阶段访问控制 (上下文相关访问控制)&#xff0c;与其相应的访问控制漏洞为也垂直越权漏洞(普通用户可以访问或…

C++:模板进阶与继承

模板进阶与继承 模板进阶1.非类型的模板参数2.模板的特化2.1特化的概念2.2函数模板特化2.3类模板特化2.4全特化和偏特化2.4.1全特化2.4.2偏特化 3.模板的分离编译3.1同文件分离3.2不同文件下分离 继承1.继承的概念和定义1.1继承的概念1.2继承的定义1.2.1定义格式1.2.2继承关系和…

找不到vcomp100.dll解决教程,一键修复vcomp100.dll丢失问题

vcomp100.dll是一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;。DLL文件是Windows操作系统中的重要组件&#xff0c;它们包含可由多个程序共享的代码和数据。通过使用DLL文件&#xff0c;程序可以实现模块化设计&#xff0c;提高代码的可重用性和可维护性。如果电…

区块链、隐私计算、联邦学习、人工智能的关联

目录 前言 1.区块链 2.隐私计算 3.联邦学习&#xff08;隐私计算技术&#xff09; 4.区块链和联邦学习 5.区块链和人工智能 展望 参考文献 前言 区块链公开透明&#xff0c;但也需要隐私&#xff0c;人工智能强大&#xff0c;但也需要限制。当前我们需要的是一个在保证…

gin 框架的 JSON Render

gin 框架的 JSON Render gin 框架默认提供了很多的渲染器&#xff0c;开箱即用&#xff0c;非常方便&#xff0c;特别是开发 Restful 接口。不过它提供了好多种不同的 JSON Render&#xff0c;那么它们的区别是什么呢&#xff1f; // JSON contains the given interface obje…

2023 年 Web 安全最详细学习路线指南,从入门到入职(含书籍、工具包)【建议收藏】

第一个方向&#xff1a;安全研发 你可以把网络安全理解成电商行业、教育行业等其他行业一样&#xff0c;每个行业都有自己的软件研发&#xff0c;网络安全作为一个行业也不例外&#xff0c;不同的是这个行业的研发就是开发与网络安全业务相关的软件。 既然如此&#xff0c;那其…

linux入门---信号的理解

目录标题 如何理解计算机中的信号如何查看计算机中的信号初步了解信号的保存和发送如何向目标进程发送信号情景一&#xff1a;使用键盘发送信号情景二&#xff1a;系统调用发送信号情景三&#xff1a;硬件异常产生信号情景四&#xff1a;软件条件产生信号 核心转储信号的两个问…

【星海出品】ansible入门(三) 深入playbook

Ansible playbook常用到模板驱动jinja2 都是python编写的。Jinja2 需要至少 Python 2.4 版本来运行。 jinja2过滤器 Jinja2中的过滤器可以把一个模板表达式转换为另一个.Jinja2附带了很多这样的功能。 jinja2源码 https://github.com/pallets/jinja/blob/main/基本 API 使用 …

Linux内核编程——内核定时器

在Linux UWB Stack的内核模块实现中&#xff0c;较多的使用了内核定时器&#xff0c;本文基于fake MCPS实现中的应用为背景&#xff0c;介绍了内核定时器的使用。 1. 内核定时器 Linux内核用来控制在未来某个时间点【基于jiffies(节拍总数)】调度执行某个函数的一种机制&#x…

【安鸾靶场】实战渗透

文章目录 前言一、租房网 (150分)二、企业网站 (300分)三、SQL注入进阶 (550分) 前言 最近看到安鸾的靶场有些比较有意思就打了一下午&#xff0c;有一定难度。 一、租房网 (150分) http://106.15.50.112:8031/ 刚打开burp就报了thinkphp的代码执行 直接getshell flag&a…

华为云云耀云服务器L实例评测|基于canal缓存自动更新流程 SpringBoot项目应用案例和源码

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到各种问题&#xff0c;在解决问题的过程中学到不少和运维相关的知识。 在之前的博客中&#xff0c;介绍过canal的安装和配置&#xff0c;参考博客 拉取创建canal镜像配置相关参数 & …

【Java】HashMap 背诵版

HashMap 背诵版 1. HashMap、Hashtable 和 ConcurrentHashMap 的区别&#xff1f;1.1 线程安全&#xff1a;1.2 继承关系&#xff1a;1.3 允不允许null值&#xff1a; 2. HashMap 的数据结构2.1 什么是hash表&#xff1f;2.2 HashMap 的数据结构 3. 什么是hash冲突&#xff0c;…

1.1.OpenCV技能树--第一单元--OpenCV简介

目录 1.文章内容来源 2.OpenCV简介 3.课后习题代码复现 4.易错点总结与反思 1.文章内容来源 1.题目来源:https://edu.csdn.net/skill/practice/opencv-77f629e4593845b0bf97e74ca8ec95ae/8292?languageopencv&materialId20807 2.资料来源:https://edu.csdn.net/skill…

Go 复合数据类型之结构体与自定义类型

Go 复合数据类型之结构体与自定义类型 文章目录 Go 复合数据类型之结构体与自定义类型一、类型别名和自定义类型1.1 类型定义&#xff08;Type Definition&#xff09;简单示例 1.2 类型别名简单示例 1.3 类型定义和类型别名的区别 二、结构体2.1 结构体介绍2.2 结构体的定义2.…

day-65 代码随想录算法训练营(19)图论 part 04

463.岛屿的周长 分析&#xff1a; 1.陆地的旁边是海面&#xff0c;存在周长2.陆地在边界上&#xff0c;存在周长 思路一&#xff1a;深度优先遍历 1.通过记录访问情况来访问数据 class Solution { public:int direct[4][2]{{0,1},{0,-1},{1,0},{-1,0}};int res0;void dfs(…

集群服务器

文章目录 项目名:实现集群服务器技术栈通过这项目你学到(或者复习到)实现功能编码环境json环境muduo库boost库MySql数据库登录mysql&#xff1a;查看mysql服务开启了没有&#xff1f;mysql的服务器及开发包库chat&#xff0c;表 allgroup friend groupuser offlinemessage user…

从零开始学习线性回归:理论、实践与PyTorch实现

文章目录 &#x1f966;介绍&#x1f966;基本知识&#x1f966;代码实现&#x1f966;完整代码&#x1f966;总结 &#x1f966;介绍 线性回归是统计学和机器学习中最简单而强大的算法之一&#xff0c;用于建模和预测连续性数值输出与输入特征之间的关系。本博客将深入探讨线性…

面试题: Spring中Bean的实例化和Bean的初始化有什么区别?

Spring中Bean的实例化和Bean的初始化有什么区别? 背景答案扩展知识什么是实例化什么是初始化 个人评价我的回答 背景 想换工作, 看了图灵周瑜老师的视频想记录一下, 算是学习结果的一个输出. 答案 Spring 在创建一个Bean对象时, 会先创建出一个Java对象, 会通过反射来执行…

Mac上protobuf环境构建-java

参考文献 getting-started 官网pb java介绍 maven protobuf插件 简单入门1 简单入门2 1. protoc编译器下载安装 https://github.com/protocolbuffers/protobuf/releases?page10 放入.zshrc中配置环境变量  ~/IdeaProjects/test2/ protoc --version libprotoc 3.12.1  …