一天一道Leetcode(190-230)

2024-02-13 11:18
文章标签 leetcode 230 一天 一道 190

本文主要是介绍一天一道Leetcode(190-230),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一天一道Leetcode(191-230)

文章目录

      • 一天一道Leetcode(191-230)
        • 191.位1的个数
        • 192-197. 统计词频(bash脚本题目,略)
        • 198.打家劫舍
        • 199. 二叉树的右视图
        • 200. 岛屿数量
        • 201. 数字范围按位与
        • 202. 快乐数
        • 203. 移除链表元素
        • 204. 计数质数
        • 205. 同构字符串
        • 207. 课程表
        • 208. 实现Trie(前缀树)
        • 209. 长度最小的子数组
        • 210. 课程表 II(拓扑排序,还不懂...)
        • 211. 添加与搜索单词 - 数据结构设计
        • 212. 单词搜索 II(未解决)
        • 213. 打家劫舍 II
        • 214. 最短回文串(未解决)
        • 215. 数组中的第k个最大元素
        • 216. 组合总和 II
        • 217. 存在重复元素
        • 218. 天际线问题(未解决)
        • 219. 存在重复元素 II
        • 220. 存在重复元素 III
        • 221. 最大正方形
        • 222. 完全二叉树的节点个数
        • 223. 矩形面积
        • 224. 基本计算器
        • 225. 用队列实现栈
        • 226. 翻转二叉树
        • 227. 基本计算器
        • 228. 汇总区间
        • 229. 求众数 II
        • 230. 二叉搜索树中第k小的元素

191.位1的个数

题目

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为’1’的个数(也成为汉明重量)

实例

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
# 将数字转化为“二进制”字符串,然后看字符串中为“1”的count个数
class Solution:def hammingWeight(self, n):n = bin(n)return n.count('1')
192-197. 统计词频(bash脚本题目,略)
198.打家劫舍

题目

一个专业小偷,计划偷窃沿街房屋。每间房内都藏有一定的现金,影响偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警,给定一个代表每个房屋存放金额的非负整数数组,计算不触动报警装置的情况下,一夜之内能够偷窃到的最高金额

实例

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。偷窃到的最高金额 = 2 + 9 + 1 = 12

思路

动态规划

  • 状态定义:

    • 设动态规划列表dp,dp[i]代表前i个房子在满足条件的情况下能偷窃到的最高金额
  • 转移方程:

    • 设:有n个房子,前n间能偷窃到的最高金额是dp[n],前n - 1间能偷窃到的最高金额是dp[n - 1],此时向这些房子后加一间房子,此房间的价值为num

    • 加一间房后:由于不能抢相邻的房子,意味着抢第n + 1间就不能抢第n间;那么前n + 1间房能偷取到的最高金额dp[n + 1]一定是以下两种情况的较大值:

      1.不抢第n + 1个房间,因此等于前n个房子的最高金额,即dp[n + 1] = dp[n];

      2.抢第n + 1个房间,此时不能抢第n个房间;因此等于前n - 1个房子的最高金额加上当前房间的价值,即dp[n + 1] = dp[n - 1] + num

    • 难道在前n间的最高金额dp[n]情况下,第n间一定被偷了么?,假设没有被偷,那么n + 1间的最大值应该也可能是dp[n + 1] = dp[n] + num,其实这种假设的情况可以被省略,因为:

      1.假设第n间没有被偷,那么此时dp[n] = dp[n - 1],此时dp[n + 1] = dp[n] + num = dp[n - 1] + num,即两种情况合并为一种

      2.假设第n间被偷,那么此时dp[n + 1] = dp[n] + num不可取,因为偷了第n间,就不能偷第n + 1间

    • 最终的转移方程:dp[n + 1] = max(dp[n], dp[n - 1] + num)

class Solution:def rob(self, nums):cur, pre = 0, 0for num in nums:cur, pre = max(pre + num, cur), cur# 为什么不能写成以下形式:# cur = max(pre + num, cur)# pre = cur# 因为pre需要接收原来的cur值,而不是更新后的cur值,可以写成以下形式:# tmp_cur = cur# cur = max(pre + num, cur)# pre = tmp_curreturn cur
199. 二叉树的右视图

题目

给定一棵二叉树,想象站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值

实例

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:1            <---/   \
2     3         <---\     \5     4       <---

思路

BFS

1.用到deque结构来模拟队列

2.队列里有一个初始节点

3.每次处理从队列中出队一个元素

4.对元素进行扩张

5.对扩张后满足某条件的节点再进行处理,根据需要进入队列,进入队列的点就是扩到下一层的点

6.然后接着循环处理deque中的元素,直到deque为空,则代表所有节点都已完成扩张

class Solution:def rightSideView(self, root):if not root: return []res = []# 构建一个队列tmp_layer = collections.deque()# 将初始节点压入tmp_layer.append(root)while len(tmp_layer):# count用来记录时某一层的第几个元素count = 0next_layer = []# 大循环,处理某一层的节点while len(tmp_layer):# 由于只要最右侧的元素,所以下面先压入队列的是右子树,然后压入左子树,只需要队列中的第一个元素tmp_node = tmp_layer.popleft()                if count == 0:res.append(tmp_node.val)count += 1# 将某个节点的右子树压入if tmp_node.right is not None:next_layer.append(tmp_node.right)# 将某个节点的左子树压入if tmp_node.left is not None:next_layer.append(tmp_node.left)# 更新下一层的tmptmp_layer = collections.deque(next_layer)return res
200. 岛屿数量

题目

给你一个由’1’(陆地)和’0’(水)组成的二维网格,计算网格中岛屿的数量(岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成),可以假设该网格的四条边均被水包围

实例

输入:grid = [["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]
]
输出:1
输入:grid = [["1","1","0","0","0"],["1","1","0","0","0"],["0","0","1","0","0"],["0","0","0","1","1"]
]
输出:3

思路

BFS

如果发现一个陆地,便对其进行BFS,并将可由BFS访问到的点的都置为已经访问的状态,从而代表同属一个岛屿

class Solution:def numIslands(self, grid):count = 0for row in range(len(grid)):for col in range(len(grid[0])):# 发现陆地if grid[row][col] == '1':count += 1 # 结果加1# 将其转化为0,表示已经访问过# 对发现的陆地进行扩张,即执行BFS操作,将与其相邻的陆地都标记为已经访问,下面是BFS过程grid[row][col] = '0'land_positions = collections.deque()land_positions.append([row, col])while len(land_positions):x, y = land_positions.popleft()# 对四个方向进行扩张for new_x, new_y in [[x, y+1], [x, y-1], [x+1, y], [x-1, y]]:# 判断有效性if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and grid[new_x][new_y] == '1':# 因为可由BFS访问到,代表同属一块岛,将其置0,代表已访问过grid[new_x][new_y] = '0'land_positions.append([new_x, new_y])return count
201. 数字范围按位与

题目

给定范围[m, n],其中0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含m, n两端点)

实例

输入: [5,7]
输出: 4
输入: [0,1]
输出: 0

思路

考虑范围[m, n],如果n比m二进制位数高,在累计按位与的过程中,数字的每一个二进制位数必然都出现过0,所以一旦出现位数不同的情况,结果必然为0

程序中,m, n在向右移位的过程中,如果m, n相等了,就说明累计按位与的左边肯定等于m, n此时的状态,这时就可以向左移回来,相当于右边所有位数都补0,相等的部分照旧

如果m, n位数不相等,肯定回移动到底,两者都为0时才会相等停止循环,这时再向左移动多少结果都是0

class Solution:def rangeBitwiseAnd(self, m, n):t = 0while m != n:m >>= 1n >>= 1t += 1return n << t
202. 快乐数

题目

编写一个算法来判断一个数n是不是快乐数

快乐数:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为1,也可能时无限循环但始终变不到1,如果可以变为1,那么这个数就是快乐数

输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
# 用一个容器记录已经出现过的数
class Solution:def isHappy(self, n):n = str(n)visited = set()while True:n = str(sum(int(i) ** 2 for i in n))if n == '1':return Trueif n in visited:return Falsevisited.add(n)
203. 移除链表元素

题目

删除链表中等于给定值val的所有节点

实例

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
# 迭代
class Solution:def removeElements(self, head, val):tmp = ListNode(0)tmp.next = headprev = tmplast = prev.nextwhile last:if last.val == val:prev.next = last.nextlast = prev.nextelse:prev = prev.nextlast = prev.nextreturn tmp.next
# 递归
class Solution:def removeElements(self, val):if not head: return head.next = self.removeElements(head.next, val)return head.next if head.val == val else head
204. 计数质数

题目

统计所有小于非负整数n的质数的数量

实例

输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 
输入:n = 0
输出:0
输入:n = 1
输出:0
# 笨办法,超时了
class Solution:def countPrimes(self, n):count = 0def is_prime(n):if n > 1:for i in range(2, n):if n % i == 0:return Falsereturn Truefor num in range(2, n):if is_prime(num):count += 1return count
# 厄拉多塞筛法
class Solution:def countPrime(self, n):# 给每个位置立一个flag,初始化为1isPrime = [1] * n# 创建计数器res = 0# 循环,从最小质数i开始到n循环for i in range(2, n):# 如果这个位置的Flag为1,说明数字i没有被比i小的整数除过,说明它是质数,计数+1if isPrimes[i] == 1: res += 1# 同时,i的倍数一定不是质数,将这些数的flag置为0# 设置背书j,初始化与i相等,因为i也是一点点加上来的,比如i=5时,i的4倍一定在i=4时设置为0过j = i# 当i的j倍大于n的时候跳出循环while i * j < n:# 设置i的j倍的flag为0isPrime[i * j] = 0# 自增,下一个找j + 1倍j += 1return res
# 进一步优化
class Solution:def countPrimes(self, n):if n < 2: return 0isPrimes = [1] * n# 设置0和1位为0isPrimes[0] = isPrimes[1] = 0# 在2到根号n的范围内,当一个数时质数,将它所有的比n小的倍数设置成0for i in range(2, int(n ** 0.5) + 1):if isPrimes[i] == 1:isPrimes[i * i: n: i] = [0] * len(isPrimes[i * i: n: i])return sum(isPrimes)
205. 同构字符串

题目

给定两个字符串s和t,判断他们是否是同构的(如果s中的字符串可以被替换得到t,那么这两个字符串是同构的),所有出现的字符都必须用另一个字符替换,同时保留字符的顺序,两个字符不能映射到同一个字符上,但字符可以映射自己本身。(s和t有相同长度)

实例

输入: s = "egg", t = "add"
输出: true
输入: s = "foo", t = "bar"
输出: false
输入: s = "paper", t = "title"
输出: true
class Solution:def isIsomorphic(self, s, t):if not s: return Truedic = dict()for i in range(len(s)):if s[i] not in dic:if t[i] in dic.values():return Falseelse:dic[s[i]] = t[i]else:if dic[s[i]] != t[i]:return Falsereturn True
207. 课程表

题目

这个学期必须选修numCourse门课程,记为0到numCourse - 1,再选修某些课程之前需要一些先修课程,例如,想要学习课程0,需要先完成课程1,用一个匹配来表示他们[0, 1]

给定课程的总量以及他们的先决条件,请判断是否可能完成所有课程的学习?

实例

输入: 2, [[1,0]] 
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

思路

广度优先遍历

1.统计课程安排图中每个节点的入度,生成入度表indegrees

2.借助一个队列,将所有入度为0的节点入队

3.当queue非空时,一次将队首节点出队,再课程安排图中删除此节点pre:

  • 并不是真正从邻接表中删除此节点pre,而是将此节点对应所有邻接节点cur的入度-1,即indegrees[cur] -= 1
  • 当入度-1后邻接节点cur的入度为0,说明cur所有的前驱节点已经被“删除”,此时将cur入队

4.在每次pre出队时,执行numCourses–;

  • 若整个课程安排时有向无环图(即可以安排),则所有节点一定都入队并出队过,即完成拓扑排序,换个角度说,如果课程安排图中存在环,一定又节点的入度始终不为0
  • 因此,拓扑排序出队次数等于课程个数,返回numCourses == 0判断课程是否可以成功安排
class Solution:def canFinish(self, numCourses, prerequisites):from collections import dequeindegrees = [0 for _ in range(numCourses)]adjacency = [[] for _ in range(numCourses)]queue = deque()for cur, pre in prerequisites:indegrees[cur] += 1adjacency[pre].append(cur)for i in range(len(indegrees)):if not indegrees[i]:queue.append(i)while queue:pre = queue.popleft()numCourses -= 1for cur in adjacency[pre]:indegrees[cur] -= 1if not indegrees[cur]:queue.append(cur)return not numCourses
208. 实现Trie(前缀树)

题目

实现一个Trie(前缀树),包含insert, search, 和startsWith这三个操作

实例

Trie trie = new Trie();trie.insert("apple");
trie.search("apple");   // 返回 true
trie.search("app");     // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");   
trie.search("app");     // 返回 true
class Solution:def __init__(self):self.lookup = {}def insert(self, word):tree = self.lookupfor a in word:if a not in tree:tree[a] = {}tree = tree[a]tree['#'] = '#'def search(self, word):tree = self.lookupfor a in word:if a not in tree:return Falsetree = tree[a]if '#' in tree:return Truereturn Falsedef startsWith(self, prefix):tree = self.lookupfor a in prefix:if a not in tree:return Falsetree = tree[a]return True
209. 长度最小的子数组

题目

给定一个含有n个正整数的数组和一个正整数s,找出该数组中满足其和>= s的长度最小的连续子数组,并返回其长度,如果不存在符合条件的子数组,返回0

实例

输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组
# 滑动窗口
class Solution:def minSubArrayLen(self, s, nums):if not nums: return 0left = 0cur = 0res = float('inf')# 设置right指针,并累加数组结果for right in range(len(nums)):cur += nums[right]# 当当前累加结果大于目标值,用累加结果减去left对应的值,同时left右移一位while cur >= s:res = min(res, right - left + 1)cur -= nums[left]left += 1return res if res != float('inf') else 0
# 前缀和 + 二分搜索
class Solution:def minSubArrayLen(self, s, nums):if not nums: return 0for i in range(1, len(nums)):nums[i] == nums[i - 1]if nums[-1] < s:return 0res = float('inf')nums = [0] + numsfor i in range(1, len(nums)):if nums[i] - s >= 0:loc = bisect.bisect_left(nums, nums[i] - s)if nums[i] - nums[loc] >= s:res = min(res, i - loc)continueif loc > 0:res = min(res, i - loc + 1)return res
210. 课程表 II(拓扑排序,还不懂…)

题目

现在共有n门课程需要选,记为0到n-1,在选修某些课程之前需要一些先修课程,例如,想要学习课程0,需要先完成课程1,用一个匹配来表示他们:[0, 1]

给定课程总量以及他们的先决条件,返回为了学完所有课程安排的学习顺序,可能会有多个正确顺序,只需要返回一种即可,如果不可能完成所有课程,返回一个空数组

实例

输入: 2, [[1,0]] 
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1]
输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]
211. 添加与搜索单词 - 数据结构设计

题目

设计一个数据结构,支持添加新单词和查找字符串是否与任何先前添加的字符串匹配,实现词类WordDictionary:

  • WordDictionary()初始化词典对象
  • void addWord(word)将word添加到数据结构中,之后可以对它进行匹配
  • bool search(word)如果数据结构中存在字符串与word匹配,则返回true,否则返回false,word中可能包含一些'.',每个.,都可以表示任何一个字母

实例

["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
输出:
[null,null,null,null,false,true,true,true]解释:
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True
class WordDictionary:def __init__(self):from collections import defaultdictself.lookup = {}def addWord(self, word):tree = self.lookupfor a in word:tree = tree.setdefault(a, {})tree['#'] = {}def search(self, word):def helper(word, tree):if not word:if '#' in tree:return Truereturn Falseif word[0] == '.':for t in tree:if helper(word[1:], tree[t]):return Trueelif word[0] in tree:if helper(word[1:], tree[word[0]]):return Truereturn Falsereturn helper(word, self.lookup)
212. 单词搜索 II(未解决)
213. 打家劫舍 II

题目

一个专业小偷,计划偷窃沿街房屋,每间房内都藏有一定现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的,同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋再同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算在不触动警报装置的情况下,能够偷窃到的最高金额

实例

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 
输入:nums = [0]
输出:0

思路

环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题简化成两个单排排列房子问题

1.在不偷窃第一个房子的情况下(即nums[1:]),最大金额是p1

2.在不偷窃最后一个房子的情况下(即nums[: n-1]),最大金额是p2

综合偷窃最大金额:为以上两种情况的较大值,即max(p1, p2)

class Solution:def rob(self, nums):def my_rob(nums):cur, pre = 0, 0for num in nums:cur, pre = max(pre + num, cur), curreturn curreturn max(my_rob(nums[:-1]), my_rob(nums[1:])) if len(nums) != 1 else nums[0]
214. 最短回文串(未解决)
215. 数组中的第k个最大元素

题目

在未排序的数组中找到第k个最大的元素,需要找的是数组排序后的第k个最大元素,而不是第k个不同的元素

实例

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
class Solution:def findKthLargest(self, nums, k):if not nums: return Nonenums = sorted(nums, reverse=True)return nums[k-1]
216. 组合总和 II

题目

找出所有相加之和为n的k个数的组合,组合中只允许含有1-9的正整数,并且每种组合中不存在重复数字

实例

输入: k = 3, n = 7
输出: [[1,2,4]]
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]

思路

回溯+剪枝

1.初始化结果数组res

2.定义回溯函数help(count, i, tmp, target),其中count表示当前已经使用的数字数,i表示当前访问的数字,tmp表示当前中间结果,target表示下一步的目标和

  • 若count == k,说明已经使用了k个数:
    • 若target == 0,表示tmp的和等于n,将tmp加入res
    • return
  • 遍历区间[i, 10]:
    • 剪枝,若j > target,说明接下来的数字都比目标和大,break
    • 执行回溯help(count + 1, j + 1, tmp + [j], target - j)

3.执行help(0, 1, [], n)

4.返回res

class Solution:def combinationSum3(self, k, n):res = []def helper(count, i, tmp, target):if count == k:if target == 0:res.append(tmp)return for j in range(i, 10):if j > target:breakhelper(count+1, j+1, tmp+[j], target-j)helper(0, 1, [], n)return res
217. 存在重复元素

题目

给定一个整数数组,判断是否存在重复元素,如果任意一值在数组中出现至少两次,返回True,如果每个元素都不相同,返回False

实例

输入: [1,2,3,1]
输出: true
输入: [1,2,3,4]
输出: false
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
class Solution:def containsDuplicate(self, nums):dic = {}for num in nums:if num not in dic:dic[num] = 1else:dic[num] += 1for ele in dic.values():if ele != 1:return Truereturn False
# -----------------------------------------
class Solution:def containsDuplicate(self, nums):dic = {}for num in nums:if dic.get(num):return Truedic[num] = 1return False
# ---------------------------------------------
class Solution:def containsDuplicate(self, nums):return len(nums) != len(set(nums))
218. 天际线问题(未解决)
219. 存在重复元素 II

题目

给定一个整数数组和一个整数k,判断数组中是否存在两个不同的索引i和j,使得nums[i] = nums[j],并且i和j的差绝对值至多为k

实例

输入: nums = [1,2,3,1], k = 3
输出: true
输入: nums = [1,0,1,1], k = 1
输出: true
输入: nums = [1,2,3,1,2,3], k = 2
输出: false
class Solution:def containsNearbyDuplicate(self, nums, k):dic = {}for key, v in enumerate(nums):if v not in dic or (key - dic[v]) > k:dic[v] = keyelse:return Trueelse:return False
220. 存在重复元素 III

题目

在整数数组nums中,是否存在两个下标i, j,使得nums[i]和nums[j]的差的绝对值小于等于t,且满足i和j的差的绝对值也小于等于k

实例

输入: nums = [1,2,3,1], k = 3, t = 0
输出: true
输入: nums = [1,0,1,1], k = 1, t = 2
输出: true
输入: nums = [1,5,9,1,5,9], k = 2, t = 3
输出: false

思路

定义桶的大小是t + 1, nums[i] // (t + 1)决定放入几号桶,这样在一个桶里面的任意两个的绝对值差值都<= t

先不考虑索引差值最大为k的限制,那么遍历nums每一个元素,并把他们放入相应的桶中,有两种情况会返回True

  • 要放入的桶已经有其他元素了,这时将nums[i]放进去满足差值<= t
  • 可能存在前面一个桶的元素并且与nums[i]的差值<= t或者存在后面一个桶的元素并且与nums[i]的差值<= t

根据返回True的第一个条件,可以知道后面桶的元素最多也只能有一个

接着考虑限制桶中的索引差最大为k,当i >= k时:需要删除存放着nums[i - k]的那个桶(编号为nums[i-k] // (t + 1) )

这样就能保证遍历到第i+1个元素时,全部桶中元素的索引最小值是i - k + 1,就满足题目对索引的限制了

class Solution:def containsNearbyAlmostDuplicate(self, nums, k, t):if t < 0 or k < 0:return Falseall_buckets = {}# 将桶的大小设置为t+1bucket_size = t + 1for i in range(len(nums)):# 决定放入哪个桶bucket_num = nums[i] // bucket_size# 如果桶中已经有元素了,将nums[i]放入桶中if bucket_num in all_buckets:return Trueall_buckets[bucket_num] = nums[i]if (bucket_num - 1) in all_buckets and abs(all_buckets[bucket_num - 1] - nums[i]) <= t:return Trueif (bucket_num + 1) in all_buckets and abs(all_buckets[bucket_num + 1] - nums[i]) <= t:return True# 如果不构成返回条件,那么当i >= k 时就要删除旧桶,以维持桶中的元素索引跟下一个i+1索引只差不超过kif i >= k:all_buckets.pop(nums[i-k] // bucket_size)return False
221. 最大正方形

题目

在一个由’0’和’1’组成的二维矩阵内,找到只包含’1’的最大正方形,并返回其面积

实例

在这里插入图片描述

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:4

思路

动态规划

dp[i][j]代表以i, j为正方形右下角的最大表厂是多少

状态转移方程:在matrix[i][j]==1的情况下dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][-1]) + 1

class Solution:def maximalSquare(self, matrix):if not matrix: return 0row = len(matrix)col = len(matrix[0])dp = [[0] * (col + 1) for _ in range(row + 1)]res = 0for i in range(1, row+1):for j in range(1, col+1):if matrix[i-1][j-1] == '1':dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1res = max(res, dp[i][j] ** 2)return res
222. 完全二叉树的节点个数

题目

给出一个完全二叉树,求出该树的节点个数

说明

完全二叉树:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为h层,则该层包含1~ 2 h 2^h 2h个节点

实例

输入: 1/ \2   3/ \  /
4  5 6输出: 6
class Solution:def countNodes(self, root):if not root: return 0left_height = 0left_node = rootright_height = 0right_node = rootwhile left_node:left_node = left_node.leftleft_height += 1while right_node:right_node = right_node.rightright_height += 1if left_height == right_height:return pow(2, left_height) - 1return 1 + self.countNodes(root.left) + self.countNodes(root.right)
223. 矩形面积

题目

在二维平面上计算出两个由直线构成的矩形重叠后形成的总面积。每个矩形由其左下顶点和右上顶点坐标表示

在这里插入图片描述

实例

输入: -3, 0, 3, 4, 0, -1, 9, 2
输出: 45
class Solution:def computeArea(self, A, B, C, D, E, F, G, H):# 调整两个矩形位置,让第一个矩形靠左边if A > E:return self.computeArea(E, F, G, H, A, B, C, D)if B >= H or D <= F or C <= E:return abs(A - C) * abs(B - D) + abs(E - G) * abs(F - H)down = max(A, E)up = min(C, G)left = max(B, F)right = min(D, H)return abs(A - C) * abs(B - D) + abs(E - G) * abs(F - H) - abs(up - down) * abs(left - right)
224. 基本计算器

题目

实现一个基本的计算器来计算一个简单的字符串表达式s的值

实例

输入:s = "1 + 1"
输出:2
输入:s = " 2-1 + 2 "
输出:3
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23

class Solution:def calculate(self, s):res = 0stack = []sign = 1i = 0n = len(s)while i < n:if s[i] == '':i += 1elif s[i] == '-':sign = -1i += 1elif s[i] == '+':sign = 1i += 1elif s[i] == '(':stack.append(res)stack.append(sign)res = 0sign = 1i += 1elif s[i] == ')':res = res * stack.pop() + stack.pop()i += 1# isdigit()检测字符串是否只由数字组成elif s[i].isdigit():tmp = int(s[i])i += 1while i < n and s[i].isdigit():tmp = tmp * 10 + int(s[i])i += 1res += tmp * signreturn res
225. 用队列实现栈

题目

使用队列实现栈的下列操作:

  • push(x) – 元素x入栈
  • pop() – 移除栈顶元素
  • top() – 获取栈顶元素
  • empty() – 返回栈是否维空
class MyStack:def __init__(self):self.q = []def push(self, x):self.q.append(x)q_length = len(self.q)while q_length > 1:self.q.append(self.q.pop(0))q_length -= 1def pop(self):return self.q.pop(0)def top(self):return self.q[0]def empty(self):return not bool(self.q)
226. 翻转二叉树

题目

翻转一棵二叉树

实例

     4/   \2     7/ \   / \
1   3 6   9
  	 4/   \7     2/ \   / \
9   6 3   1
# 递归
class Solution:def invertTree(self, root):if not root: return Noneroot.left, root.right = root.right, root.leftself.invertTree(root.left)self.invertTree(root.right)return root
# 迭代
class Solution:def invertTree(self, root):if not root: return Nonefrom collections import dequequeue = deque()queue.append(root)while queue:node = queue.popleft()node.left, node.right = node.right, node.leftif node.left:queue.append(node.left)if node.right:queue.append(node.right)return root
227. 基本计算器

题目

实现一个基本的计算器来计算一个简单的字符串表达式的值,字符串表达式仅包含非负整数,+, -, *, / 四种运算符和空格,整数除法仅保留整数部分

实例

输入: "3+2*2"
输出: 7
输入: " 3/2 "
输出: 1
输入: " 3+5 / 2 "
输出: 5
class Solution:def calculate(self, s):stack = []num, sign = 0, '+'for i in range(len(s)):if s[i].isdigit():num = num * 10 + int(s[i])if s[i] in '+-*/' or i == len(s) - 1:if sign == '+':stack.append(num)elif sign == '-':stack.append(-num)elif sign == '*':stack.append(stack.pop() * num)else:stack.append(int(stack.pop() / num))num = 0sign = s[i]return sum(stack)
228. 汇总区间

题目

给定一个无重复元素的有序整数数组nums,返回恰好覆盖数组中所有数字的最小有序区间范围列表,也就是说nums的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于nums的数字x

实例

输入:nums = [0,1,2,4,5,7]
输出:["0->2","4->5","7"]
解释:区间范围是:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"
输入:nums = [0,2,3,4,6,8,9]
输出:["0","2->4","6","8->9"]
解释:区间范围是:
[0,0] --> "0"
[2,4] --> "2->4"
[6,6] --> "6"
[8,9] --> "8->9"
输入:nums = []
输出:[]
输入:nums = [-1]
输出:["-1"]
输入:nums = [0]
输出:["0"]
class Solution:def summaryRanges(self, nums):n = len(nums)# 初始化双指针,均指向数组头部left = 0right = 0ans = []# 开始遍历while right < n:# 数组有序,先限定边界,查找间隔大于1的部分while right < n - 1 and nums[right] + 1 == nums[right + 1]:right += 1# 找到间隔后,将前面连续部分按照规定格式添加到结果列表中tmp = [str(nums[left])]if nums[left] != nums[right]:tmp.append('->')tmp.append(str(nums[right]))ans.append(''.join(tmp))# 维护更新right和leftright += 1left = rightreturn ans
229. 求众数 II

题目

给定一个大小为n的整数数组,找出其中所有出现超过 ⌊ n / 3 ⌋ \lfloor n/3\rfloor n/3次的元素,尝试设计时间复杂度为O(n)、空间复杂度为O(1)的算法

实例

输入:[3,2,3]
输出:[3]
输入:nums = [1]
输出:[1]
输入:[1,1,1,3,3,2,2,2]
输出:[1,2]

思路

摩尔投票法

核心:每次都拿走3个不一样的数,那么最后剩下的一定是A, B
在这里插入图片描述
拿走的三个数抵消可以分为三种情况:

1.包括A、B

将柱形图的三个柱形都减一,得到新的柱形图最高的仍然是A、B,不影响最终结果

2.只包括A、B其中一个,假设是A

虽然A减少了1,但是其他数的柱形图也减少了1, 得到的新柱形图最高的仍然是A,B,不影响最终结果

3.都不包括A、B

其他数的柱形减少,得到的新柱形图仍然是A、B最高,不影响最终结果

class Solution:def majorityElement(self, nums):a, b, count_a, count_b = 0, 0, 0, 0res = []for i in nums:if a == i:count_a += 1continueif b == i:count_b += 1continueif count_a == 0:a = icount_a = 1continueif count_b == 0:b = icount_b = 1continuecount_a -= 1count_b -= 1count_a, count_b = 0, 0for j in nums:if j == a:count_a += 1elif j == b:count_b += 1if count_a > len(nums) / 3:res.append(a)if count_b > len(nums) / 3:res.append(b)return res
230. 二叉搜索树中第k小的元素

题目

给定一个二叉搜索树,编写一个函数kthSmallest来查找其中第k个最小的元素

实例

输入: root = [3,1,4,null,2], k = 13/ \1   4\2
输出: 1
输入: root = [5,3,6,2,4,null,null,1], k = 35/ \3   6/ \2   4/1
输出: 3
# 递归
class Solution:def kthSmallest(self, root, k):res = Nonedef helper(root):# nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量nonlocal k, resif root.left: helper(root.left)k -= 1if k == 0:res = root.valreturn if root.right: helper(root.right)helper(root)return res
# 迭代
class Solution:def kthSmallest(self, root, k):cur = rootstack = []while cur or stack:while cur:stack.append(cur)cur = cur.lefttmp = stack.pop()k -= 1if k == 0:return tmp.valif tmp.right:cur = tmp.rightcount_b = 1continuecount_a -= 1count_b -= 1count_a, count_b = 0, 0for j in nums:if j == a:count_a += 1elif j == b:count_b += 1if count_a > len(nums) / 3:res.append(a)if count_b > len(nums) / 3:res.append(b)return res

这篇关于一天一道Leetcode(190-230)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/705396

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

【多系统萎缩患者必看】✨维生素补充全攻略,守护你的健康每一天!

亲爱的朋友们,今天我们要聊一个既重要又容易被忽视的话题——‌多系统萎缩患者如何科学补充维生素‌!🌟 在这个快节奏的生活中,健康成为了我们最宝贵的财富,而对于多系统萎缩(MSA)的患者来说,合理的营养补充更是维护身体机能、提升生活质量的关键一步。👇 🌈 为什么多系统萎缩患者需要特别关注维生素? 多系统萎缩是一种罕见且复杂的神经系统疾病,它影响身体的多个系统,包括自主神经、锥体外系、小脑及锥

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划