LeetCode部分题解(一)
一、前言
因为这周选的题单太难把我这个蒟蒻打崩了╮(╯﹏╰)╭这周我带来了一些LeetCode的题解,因为刚开始写,也是第一次尝试Python写,所以选的题难度也不大。也是防止打牛客小白赛再在简单题翻车┭┮﹏┭┮
二、go go go
1、1689. 十-二进制数的最少数目
如果一个十进制数字不含任何前导零,且每一位上的数字不是 0 就是 1 ,那么该数字就是一个 十-二进制数 。例如,101 和 1100 都是 十-二进制数,而 112 和 3001 不是。
给你一个表示十进制整数的字符串 n ,返回和为 n 的 十-二进制数 的最少数目。
示例 1:
输入:n = “32”
输出:3
解释:10 + 11 + 11 = 32
示例 2:
输入:n = “82734”
输出:8
示例 3:
输入:n = “27346209830709182346”
输出:9
提示:
1 <= n.length <= 105
n 仅由数字组成
n 不含任何前导零并总是表示正整数
这道题真的简单,给了三个样例,所以直接秒解,显然是每位数中最大的那个,Python更是一行秒。
AC code
class Solution:
def minPartitions(self, n: str) -> int:
return int(max(n))
1476. 子矩形查询
请你实现一个类 SubrectangleQueries
,它的构造函数的参数是一个 rows x cols
的矩形(这里用整数矩阵表示),并支持以下两种操作:
1.updateSubrectangle(int row1, int col1, int row2, int col2, int newValue)
- 用
newValue
更新以(row1,col1)
为左上角且以(row2,col2)
为右下角的子矩形。
2.getValue(int row, int col)
- 返回矩形中坐标
(row,col)
的当前值。
示例 1:
输入:
["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue","getValue"]
[[[[1,2,1],[4,3,4],[3,2,1],[1,1,1]]],[0,2],[0,0,3,2,5],[0,2],[3,1],[3,0,3,2,10],[3,1],[0,2]]
输出:
[null,1,null,5,5,null,10,5]
解释:
SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,2,1],[4,3,4],[3,2,1],[1,1,1]]);
// 初始的 (4x3) 矩形如下:
// 1 2 1
// 4 3 4
// 3 2 1
// 1 1 1
subrectangleQueries.getValue(0, 2); // 返回 1
subrectangleQueries.updateSubrectangle(0, 0, 3, 2, 5);
// 此次更新后矩形变为:
// 5 5 5
// 5 5 5
// 5 5 5
// 5 5 5
subrectangleQueries.getValue(0, 2); // 返回 5
subrectangleQueries.getValue(3, 1); // 返回 5
subrectangleQueries.updateSubrectangle(3, 0, 3, 2, 10);
// 此次更新后矩形变为:
// 5 5 5
// 5 5 5
// 5 5 5
// 10 10 10
subrectangleQueries.getValue(3, 1); // 返回 10
subrectangleQueries.getValue(0, 2); // 返回 5
示例 2:
输入:
["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue"]
[[[[1,1,1],[2,2,2],[3,3,3]]],[0,0],[0,0,2,2,100],[0,0],[2,2],[1,1,2,2,20],[2,2]]
输出:
[null,1,null,100,100,null,20]
解释:
SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,1,1],[2,2,2],[3,3,3]]);
subrectangleQueries.getValue(0, 0); // 返回 1
subrectangleQueries.updateSubrectangle(0, 0, 2, 2, 100);
subrectangleQueries.getValue(0, 0); // 返回 100
subrectangleQueries.getValue(2, 2); // 返回 100
subrectangleQueries.updateSubrectangle(1, 1, 2, 2, 20);
subrectangleQueries.getValue(2, 2); // 返回 20
提示:
- 最多有
500
次updateSubrectangle
和getValue
操作。 1 <= rows, cols <= 100
rows == rectangle.length
cols == rectangle[i].length
0 <= row1 <= row2 < rows
0 <= col1 <= col2 < cols
1 <= newValue, rectangle[i][j] <= 10^9
0 <= row < rows
0 <= col < cols
这道题要求我们实现两个功能,一个是更新矩阵的值,一个是输出。其实可以理解为一个二维数组,改变其中一个小子数组的值,然后输出一个点,也不难。
class SubrectangleQueries:
def __init__(self, rectangle: List[List[int]]):
self.rectangle = rectangle
def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
for i in range(row1,row2+1):
for j in range(col1,col2+1):
self.rectangle[i][j] = newValue
def getValue(self, row: int, col: int) -> int:
return self.rectangle[row][col]
1480. 一维数组的动态和
给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。
请返回 nums 的动态和。
示例 1:
输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。
示例 2:
输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。
示例 3:
输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]
提示:
1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6
这道题唯一要注意就是不要一个一个算,直接线性的,用递推解决,难度也不大
AC code
class Solution:
def runningSum(self, nums: List[int]) -> List[int]:
k = len(nums)
i = 1
ans = []
ans.append(nums[0])
while i < k:
ans.append(nums[i] + ans[i-1])
i = i + 1
return ans
1672. 最富有客户的资产总量
给你一个 m x n 的整数网格 accounts ,其中 accounts[i][j] 是第 i 位客户在第 j 家银行托管的资产数量。返回最富有客户所拥有的 资产总量 。
客户的 资产总量 就是他们在各家银行托管的资产数量之和。最富有客户就是 资产总量 最大的客户。
示例 1:
输入:accounts = [[1,2,3],[3,2,1]]
输出:6
解释:
第 1 位客户的资产总量 = 1 + 2 + 3 = 6
第 2 位客户的资产总量 = 3 + 2 + 1 = 6
两位客户都是最富有的,资产总量都是 6 ,所以返回 6 。
示例 2:
输入:accounts = [[1,5],[7,3],[3,5]]
输出:10
解释:
第 1 位客户的资产总量 = 6
第 2 位客户的资产总量 = 10
第 3 位客户的资产总量 = 8
第 2 位客户是最富有的,资产总量是 10
示例 3:
输入:accounts = [[2,8,7],[7,1,3],[1,9,5]]
输出:17
提示:
m == accounts.length
n == accounts[i].length
1 <= m, n <= 50
1 <= accounts[i][j] <= 100
这道题数据量比较小,所以就是简单的加起来就行
AC code
class Solution:
def maximumWealth(self, accounts: List[List[int]]) -> int:
ans = 0
for i in range(len(accounts)):
k = 0
for j in range(len(accounts[i])):
k += accounts[i][j]
if k > ans :
ans = k
return ans
剑指 Offer 64. 求1+2+…+n
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3
输出: 6
示例 2:
输入: n = 9
输出: 45
限制:
1 <= n <= 10000
这道题还是比较有意思的,大家可以先思考一下
其实如果我们按照循环来思考的话,不能循环就只能选择递归了,所以大概方向就是递归,问题是怎么控制边界?这也是比较难想的地方。然后我们先看看能用的工具,一看到那么多关键字不能用,其实我们也就剩那些逻辑运算符和位运算符了。逻辑运算的话我们可以利用and的特性来做一个短路,也是我的解法。LeetCode官方题解也提供了另一种很好的思路。其实我看到这道题第一反应是把他用求和公式处理一下,变成一次乘法一次除法,然后用位运算解决。但我位运算太烂了O__O "…翻了半天资料也没想明白。然后LeetCode给的解法是把每位单独相乘(因为位数有限,数据不大,可以不用 循环,直接暴力)具体操作是如果b在某位上为1,则答案加上a在该位的值,挺巧妙的。
AC code
class Solution:
def sumNums(self, n: int) -> int:
return n and n + self.sumNums(n-1)
面试题 02.03. 删除中间节点
实现一种算法,删除单向链表中间的某个节点(即不是第一个或最后一个节点),假定你只能访问该节点。
示例:
输入:单向链表a->b->c->d->e->f中的节点c
结果:不返回任何数据,但该链表变为a->b->d->e->f
这就是链表的操作,我们只能访问当前的结点,而我们一般考虑的删除应该是知道一个节点的上一个节点,将他指向删除结点的下一个结点从而完成删除,现在只能访问删除结点,所以我们将删除节点赋值为删除节点的下一个结点,然后删除下一个结点
AC code
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
node.val = node.next.val
node.next = node.next.next
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
限制:
1 <= k < s.length <= 10000
是非常简单的字符串操作,但用Python写出来,和之前比较熟悉的c++相比,又精简了许多
AC code
class Solution:
def reverseLeftWords(self, s: str, n: int) -> str:
return s[n:] + s[:n]
1512. 好数对的数目
给你一个整数数组 nums 。
如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。
返回好数对的数目。
示例 1:
输入:nums = [1,2,3,1,1,3]
输出:4
解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始
示例 2:
输入:nums = [1,1,1,1]
输出:6
解释:数组中的每组数字都是好数对
示例 3:
输入:nums = [1,2,3]
输出:0
提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100
这个题要先找规律,会发现有几个好数对取决于有几个相同的数字,对与每个新数字,前面每个相同的数字都可以增加一个新的好数对,所以就是等差数列求和。
AC code
class Solution:
def numIdenticalPairs(self, nums: List[int]) -> int:
book = [0 for i in range(109)]
ans = 0
for i in range(len(nums)):
book[nums[i]] += 1
for i in range(109):
ans += (book[i] * (book[i] - 1)) / 2
return int(ans)
771. 宝石与石头
给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头。 S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。
J 中的字母不重复,J 和 S中的所有字符都是字母。字母区分大小写,因此"a"和"A"是不同类型的石头。
示例 1:
输入: J = “aA”, S = “aAAbbbb”
输出: 3
示例 2:
输入: J = “z”, S = “ZZ”
输出: 0
注意:
S 和 J 最多含有50个字母。
J 中的字符不重复。
这道题还是字符串统计,难度不大,这里我发现用book数组在时间上优势挺大的,这两道题都击败了超过93%的用户ヾ(o◕∀◕)ノヾ
AC code
class Solution:
def numJewelsInStones(self, jewels: str, stones: str) -> int:
ans = 0
book = [0 for i in range(200)]
for i in range(len(stones)):
book[ord(stones[i])] += 1
for i in range(len(jewels)):
ans += book[ord(jewels[i])]
return ans
1431. 拥有最多糖果的孩子
给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。
对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。
示例 1:
输入:candies = [2,3,5,1,3], extraCandies = 3
输出:[true,true,true,false,true]
解释:
孩子 1 有 2 个糖果,如果他得到所有额外的糖果(3个),那么他总共有 5 个糖果,他将成为拥有最多糖果的孩子。
孩子 2 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
孩子 3 有 5 个糖果,他已经是拥有最多糖果的孩子。
孩子 4 有 1 个糖果,即使他得到所有额外的糖果,他也只有 4 个糖果,无法成为拥有糖果最多的孩子。
孩子 5 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
示例 2:
输入:candies = [4,2,1,1,2], extraCandies = 1
输出:[true,false,false,false,false]
解释:只有 1 个额外糖果,所以不管额外糖果给谁,只有孩子 1 可以成为拥有糖果最多的孩子。
示例 3:
输入:candies = [12,1,12], extraCandies = 10
输出:[true,false,true]
提示:
2 <= candies.length <= 100
1 <= candies[i] <= 100
1 <= extraCandies <= 50
大家可能已经发现我选的题目有多水了w(゚Д゚)w直接上代码了
AC code
class Solution:
def kidsWithCandies(self, candies: List[int], extraCandies: int) -> List[bool]:
m = max(candies)
ans = [True for i in range(len(candies))]
for i in range(len(candies)):
if candies[i] + extraCandies < m:
ans[i] = False
return ans
1470. 重新排列数组
给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。
请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排后的数组。
示例 1:
输入:nums = [2,5,1,3,4,7], n = 3
输出:[2,3,5,4,1,7]
解释:由于 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 ,所以答案为 [2,3,5,4,1,7]
示例 2:
输入:nums = [1,2,3,4,4,3,2,1], n = 4
输出:[1,4,2,3,3,2,4,1]
示例 3:
输入:nums = [1,1,2,2], n = 2
输出:[1,2,1,2]
提示:
1 <= n <= 500
nums.length == 2n
1 <= nums[i] <= 10^3
一个循环,把之前的数列分成两个来取就好了,注意找规律即可
AC code
class Solution:
def shuffle(self, nums: List[int], n: int) -> List[int]:
ans = [0 for i in range(2*n)]
for i in range(n):
ans [2*i] = nums[i]
ans [2*i+1] = nums[i+n]
return ans
1486. 数组异或操作
给你两个整数,n 和 start 。
数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。
请返回 nums 中所有元素按位异或(XOR)后得到的结果。
示例 1:
输入:n = 5, start = 0
输出:8
解释:数组 nums 为 [0, 2, 4, 6, 8],其中 (0 ^ 2 ^ 4 ^ 6 ^ 8) = 8 。
“^” 为按位异或 XOR 运算符。
示例 2:
输入:n = 4, start = 3
输出:8
解释:数组 nums 为 [3, 5, 7, 9],其中 (3 ^ 5 ^ 7 ^ 9) = 8.
示例 3:
输入:n = 1, start = 7
输出:7
示例 4:
输入:n = 10, start = 5
输出:2
提示:
1 <= n <= 1000
0 <= start <= 1000
n == nums.length
因为数据量不大,我们直接模拟即可
AC code
class Solution:
def xorOperation(self, n: int, start: int) -> int:
nums = [start + 2 * i for i in range(n)]
ans = 0
for i in range(n):
ans = ans ^ nums[i]
return ans
LCP 01. 猜数字
小A 和 小B 在玩猜数字。小B 每次从 1, 2, 3 中随机选择一个,小A 每次也从 1, 2, 3 中选择一个猜。他们一共进行三次这个游戏,请返回 小A 猜对了几次?
输入的guess数组为 小A 每次的猜测,answer数组为 小B 每次的选择。guess和answer的长度都等于3。
示例 1:
输入:guess = [1,2,3], answer = [1,2,3]
输出:3
解释:小A 每次都猜对了。
示例 2:
输入:guess = [2,2,3], answer = [3,2,1]
输出:1
解释:小A 只猜对了第二次。
限制:
guess 的长度 = 3
answer 的长度 = 3
guess 的元素取值为 {1, 2, 3} 之一。
answer 的元素取值为 {1, 2, 3} 之一。
数列对比,开个循环,挨个比就行了,输出相同的个数
AC code
class Solution:
def game(self, guess: List[int], answer: List[int]) -> int:
res = 0
for i in range(len(guess)):
if guess[i] == answer[i]:
res += 1
return res
1720. 解码异或后的数组
未知 整数数组 arr 由 n 个非负整数组成。
经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 经编码后得到 encoded = [1,2,3] 。
给你编码后的数组 encoded 和原数组 arr 的第一个元素 first(arr[0])。
请解码返回原数组 arr 。可以证明答案存在并且是唯一的。
示例 1:
输入:encoded = [1,2,3], first = 1
输出:[1,0,2,1]
解释:若 arr = [1,0,2,1] ,那么 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]
示例 2:
输入:encoded = [6,2,7,3], first = 4
输出:[4,2,0,7,4]
提示:
2 <= n <= 10^4
encoded.length == n - 1
0 <= encoded[i] <= 10^5
0 <= first <= 10^5
这道题终于需要思考一下啦ヾ(Ő∀Ő๑)ノ但位运算大佬们肯定知道对一个数异或两次就可以得到这个数本身(因为异或同假异真的特性)所以只需要让frist和encoded数组一个一个异或就可以逐渐得到整个数组啦
AC code
class Solution:
def decode(self, encoded: List[int], first: int) -> List[int]:
ans = [0 for i in range(len(encoded)+1)]
ans[0] = first
for i in range(len(encoded)):
ans[i+1] = ans[i] ^ encoded[i]
return ans
面试题 16.01. 交换数字
编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。
示例:
输入: numbers = [1,2]
输出: [2,1]
提示:
numbers.length == 2
这道题有意思哦,当然只要给一些很奇怪的限制我们就可以往位运算上想○( ^皿^)っHiahiahia…大家可以先思考一下
其实只要异或三次即可,再次展现了位运算的强大
AC code
class Solution:
def swapNumbers(self, numbers: List[int]) -> List[int]:
numbers[0] = numbers[0] ^ numbers[1]
numbers[1] = numbers[0] ^ numbers[1]
numbers[0] = numbers[0] ^ numbers[1]
return numbers
三、小结
这周题解里面有些位运算的题还是挺有意思的。好叭这周确实有些水┭┮﹏┭┮因为LeetCode打算尽量刷完,所以会从简单题开始慢慢加难度,然后希望Python技术也随着这个过程逐渐提高,所以一开始的题稍微简单了一些哈。下周我会写一些比较厉害的东西(先立flag防鸽o(〃‘▽’〃)o)