2022年9月2日
记录一下学习历程,方便以后回顾,同时也是想起到监督作用。今天先刷刷简单题吧,太菜了 。
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
题目链接:https://leetcode.cn/problems/two-sum
## 哈希map
recode = dict() # 建立map key存列表的数据,value存数据在列表中的index
for idx,val in enumerate(nums): ## 遍历数组
if target-val not in recode: ##判断目标值与当前值的差值是否存在map中
recode[val] = idx
else:
return [recode[target-val],idx]
9.回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
题目链接:https://leetcode.cn/problems/palindrome-number
# 简单粗暴,把int直接变成str,直接比较
return str(x) == str(x)[::-1]
13.罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
题目链接:https://leetcode.cn/problems/roman-to-integer
text = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
ans = 0
#从左到右来,如果当前字符代表的值不小于其右边,就加上该值;否则就减去该值。
for i in range(len(s)):
if i<len(s)-1 and text[s[i]]<text[s[i+1]]:
ans -= text[s[i]]
else:
ans += text[s[i]]
return ans
14.最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”。
题目链接:https://leetcode.cn/problems/longest-common-prefix/
两种方法:
方法一
#### 使用zip 函数将和set函数完成
"
1、zip函数将对象中对应的元素打包成一个元组,加*会打包成一个列表
例如:
a = [1,2]
b = [4,5]
c = zip(a,b)
>> c = [(1,4),(2,5)]
2、而set函数则是将列表中重复的元素去掉
例如:
a = [1,2,1,3,2]
b = set(a)
>> b = [1,2,3]
"
ans = ""
for tup in zip(*strs):
if len(set(tup)) == 1:
ans += tup[0]
else:
break
return ans
方法2
#根据 ASCII 得到最大值和最小值的字符串
s1 = min(strs)
s2 = max(strs)
for idx,val in enumerate(s1):#遍历ASCII 最小值字符串
if val != s2[idx]: # 判断与最大的是否相同
return s1[:idx]
return s1
20.有效的括号
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
题目链接:https://leetcode.cn/problems/valid-parentheses
#堆栈的方法
stack = []
for item in s: # 遍历字符串
if item == '(':
stack.append(')') # 堆上括号的另一半 后续一样
elif item == '[':
stack.append(']')
elif item == '{':
stack.append('}')
#如果栈是空的,或者说栈的最后一个与当前字符不一样,那就返回False
elif not stack or stack[-1] != item:
return False
else:
stack.pop() ## 弹栈,把最后存入的删除掉
return True if not stack else False ## 如果栈没弹干净说明存在不成对的括号。
26.删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
题目链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array
for i in range(len(nums)-1,0,-1): ## 从后往前遍历
if nums[i] == nums[i-1]:
del nums[i]
2022年9月3日
27.移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
题目链接:https://leetcode.cn/problems/remove-element
## 大力出奇迹方法
for i in range(len(nums)-1,-1,-1):
if nums[i] == val:
nums.pop(i)
## 快慢双指针
slowIndex = fastIndex = 0
while fastIndex<len(nums):
if nums[fastIndex] != val:
nums[slowIndex] = nums[fastIndex]
slowIndex += 1
fastIndex +=1
return slowIndex
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
题目链接:https://leetcode.cn/problems/search-insert-position
# 快慢双指针
slow = 0
fast = 0
while fast < len(nums):
if nums[fast] < target:
slow += 1
fast += 1
return slow
## 暴力
for i in range(len(nums)):
if nums[i] >= target:
return i
return i+1
## 二分法
left = 0
right = len(nums)-1
while left <= right:
mid = int((left + right) / 2)
if nums[mid] > target:
right -= 1
elif nums[mid] < target:
left += 1
else:
return mid
return right+1
58. 最后一个单词的长度
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
题目链接:https://leetcode.cn/problems/length-of-last-word
## 直接把字符串切片成列表,取最后一个求取长度就行
return len(s.split()[-1] )
66. 加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
题目链接:https://leetcode.cn/problems/plus-one
## 笨方法
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
i = 0
ans = 0
for digit in reversed(digits):
ans += digit*(10**i)
i +=1
ans += 1
res = []
j = 1
while ans > 0:
mid_num = 10**(j)
res.append(ans%10)
ans =ans//10
return res[::-1]
67.二进制求和
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
题目链接:https://leetcode.cn/problems/add-binary/
这提其实完全可以用python自带的内置函数来做,也就一行代码。
return bin(int(a,2)+int(b,2))[2:]
不过既然是来学习的,那就最好自己写一写。
## 永远b是最短的
if len(a) < len(b):
a ,b = b,a
## 求取长度相差多少
diff = len(a) - len(b)
# 用0把b的长度填充和a一样长
b = "0"*diff+b
mid = 0
ans = ''
# 逆序相加
for i in range(len(a)-1,-1,-1):
# 取出对应的元素相加
res = int(a[i])+int(b[i])+mid
# 如果为2 那就进1,同时0添加到ans中
if res == 2:
mid = 1
ans = '0' + ans
# 如果是最后一位了,就要长度多加一个1
if i == 0:
ans = '1' + ans
# 如果为3 那就进1 同时1添加到ans中
elif res == 3:
mid = 1
ans = '1' + ans
if i == 0:
ans = '1' + ans
else:
mid = 0
ans = str(res) + ans
return ans
69. x 的平方根
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
题目链接:https://leetcode.cn/problems/sqrtx/
#最简单的方法,就是使用内置函数sqrt()
return int(sqrt(x))
# 另外可以用牛顿法
if x <= 1:
return x
r = x
while r > x/r:
r = (r + x/r)//2
return int(r)
70.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
题目链接:https://leetcode.cn/problems/climbing-stairs/
这是一题简单的动态规划题目,和斐波那契数 异曲同工,主要是把公式推到出来。
由题我们可以知道
n = 1 ---->>> 1
n = 2 ----->>>2
n = 3 ---->>> 3
n = 4 ---->>> 5
由此可推出 F(n)= F(n-2)+F(n-1)
class Solution:
def climbStairs(self, n: int) -> int:
ans = [1,2]
if n <=2:
return ans[n-1]
for i in range(2,n):
ans.append(ans[i-2]+ans[i-1])
return ans[-1]
509.斐波那契数
题目链接:https://leetcode.cn/problems/fibonacci-number/
class Solution:
def fib(self, n: int) -> int:
ans = [0,1]
if n<2:
return ans[n]
for i in range(2,n+1):
ans.append(ans[i-2]+ans[i-1])
return ans[-1]
2022年 9月4日
88.合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
题目链接:https://leetcode.cn/problems/merge-sorted-array
这题其实nums1的长度是m+n的,因此不需要改变nums1的长度,直接在上面处理就行
'
python的简单粗暴的方法,因为默认nums1只有前m个是非0的数字,因此直接切片后续的数字变为nums2中的元素
'
nums1[m:] = nums2
nums1.sort()
双指针,一个指向nums1,另一个指向nums2,我这里还考虑了0可能在前面的情况,如果不考虑的话,会更简单。
i = len(nums1) - 1
j = n - 1
while True:
if nums1[i] == 0:
nums1[i] = nums2[j]
i -= 1
j -= 1
else:
i -= 1
if i<0 or j <0:
break
nums1.sort()
## 这个不考虑前面有0的情况,直接按题目的意思来。
i = len(nums1) - 1
j = n - 1
while j >-1:
nums1[i] = nums2[j]
i -= 1
j -= 1
nums1.sort()
118. 杨辉三角
题目链接:https://leetcode.cn/problems/pascals-triangle/
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
results = []
for i in range(numRows):
result = [1]
for j in range(i):
if j < i-1:
result.append(results[i-1][j]+results[i-1][j+1])
else:
result.append(1)
results.append(result)
return results
119. 杨辉三角II
题目链接:https://leetcode.cn/problems/pascals-triangle-ii/
这题和杨辉三角其实是一样的,只不过返回的数据有所差别仅此而已。
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
results = []
for i in range(rowIndex+1):
result = [1]
for j in range(i):
if j < i - 1:
result.append(results[i-1][j]+results[i-1][j+1])
else:
result.append(1)
results.append(result)
return results[-1]
121.买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock
贪心算法
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 如果给的价格只有一个,那么就直接返回0
if len(prices) <= 1:
return 0
# 把第一天的价格默认为最低价
min_price = prices[0]
# 最大利润默认为 0
max_profit = 0
# 遍历价格
for price in prices:
#挑选出最低的进货价格
min_price = min(min_price,price)
## 计算当前利润
cur_profit = price - min_price
# 比较当前利润和最大利润取两者中最大值
max_profit = max(max_profit,cur_profit)
return max_profit
动态规划
class Solution:
def maxProfit(self, prices: List[int]) -> int:
days = len(prices)
dp = [[0]*days,[0]*days]
## dp 初始化
dp[0][0] = - prices[0]
dp[1][0] = 0
for i in range(1,days):
dp[0][i] = max(dp[0][i-1],-prices[i])
dp[1][i] = max(dp[1][i-1],dp[0][i-1]+prices[i])
return dp[1][-1]
592. 分数加减运算
给定一个表示分数加减运算的字符串 expression ,你需要返回一个字符串形式的计算结果。
这个结果应该是不可约分的分数,即最简分数。 如果最终结果是一个整数,例如 2,你需要将它转换成分数形式,其分母为 1。所以在上述例子中, 2 应该被转换为 2/1。
题目链接:https://leetcode.cn/problems/fraction-addition-and-subtraction
### 暴力解法
import numpy
from math import gcd
class Solution:
def fractionAddition(self, expression: str) -> str:
stack = []
## 把一个个分数切割出来成列表,如果是减法直接分子为负值。
# 如 "-1/2+1/2+1/3" --->>> [[-1,2],[1,2],[1,3]]
for i in expression.replace('-', '+-').split('+'):
if i:
stack.append(list(map(int ,i.split('/'))))
## 用zip函数,把分子和分母分开
## [[-1,1,1],[2,2,3]]
stack = list(zip(*stack))
molecule = 0
# 取出所有分子
molecules = list(stack[0])
# 取出所有分母
denominators = list(stack[1])
# 所有分母相乘 即 y1*y2*y3
denominator = int(numpy.prod(denominators))
for i in range(len(molecules)):
denominator_ = denominators[:]
denominator_.pop(i)
#分子与分母的相乘 如:x1*y2*y3
molecule += molecules[i]*numpy.prod(denominator_)
molecule = int(molecule)
denominator = int(denominator)
if molecule == 0:
return '0/1'
if molecule < 0:
molecule *= -1
g = gcd(molecule,denominator)
return '-{}/{}'.format(int(molecule/g),int(denominator/g))
else:
g = gcd(molecule, denominator)
return '{}/{}'.format(int(molecule / g), int(denominator / g))
2022年9月14日。
前段时间学习动态规划了,而且忙着找工作,还要复习一下知识点。
136.只出现一次的数字
题目链接:https://leetcode.cn/problems/single-number/
异或运算
class Solution:
def singleNumber(self, nums: List[int]) -> int:
# 异或运算
ans = 0
for num in nums:
ans ^= num
return ans
暴力解法
直接计算出现的次数,若重复出现则删掉。
class Solution:
def singleNumber(self, nums: List[int]) -> int:
nums_map = dict()
for num in nums:
if num not in nums_map:
nums_map[num] = 1
else:
del nums_map[num]
return list(nums_map.keys())[0]
用列表直接存 时间居然比用字典存的要多十多倍?这是为什么呢??
class Solution:
def singleNumber(self, nums: List[int]) -> int:
nums_map = []
for num in nums:
if num not in nums_map:
nums_map.append(num)
else:
nums_map.remove(num)
return nums_map[0]
350. 两个数组的交集 II
**分析:**其实这题的思路就是 计算nums1中各个数母的出现次数,当nums2中出现时就减去一个并保留下来.
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
# map
nums1_map = dict()
for nums in nums1:
if nums not in nums1_map:
nums1_map[nums] = 1
else:
nums1_map[nums] += 1
ans = []
for nums in nums2:
if nums in nums1_map and nums1_map[nums] != 0:
ans.append(nums)
nums1_map[nums] -= 1
return ans
## 双指针
class Solution:
def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1 = sorted(nums1)
nums2 = sorted(nums2)
if len(nums1) > len(nums2):
# 始终认为 nums1为最短的数组
nums1,nums2 = nums2,nums1
nums1_p = 0
nums2_p = 0
ans = []
while nums2_p < len(nums2) and nums1_p <len(nums1):
if nums1[nums1_p] == nums2[nums2_p]:
ans.append(nums1[nums1_p])
nums1_p += 1
nums2_p += 1
# 排序之后,谁小谁移动
elif nums1[nums1_p] < nums2[nums2_p]:
nums1_p += 1
else:
nums2_p += 1
return ans
383.赎金信
题目链接:https://leetcode.cn/problems/ransom-note/
分析:
其实这题的思路就是 计算magazine中各个字母的出现次数,当ransomNote中出现时就减去一个,若ransomNote中出现,但magazine中没有就返回False.
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
dp = [0]*26
for x in magazine:
dp[ord(x)-ord('a')] += 1
for x in ransomNote:
if dp[ord(x)-ord('a')] == 0:
return False
else:
dp[ord(x)-ord('a')] -= 1
return True
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
magazineCout = dict()
ransomNoteCout = dict()
if len(ransomNote)>len(magazine):
return False
for s in magazine:
if s not in magazineCout:
magazineCout[s] = 1
else:
magazineCout[s] +=1
for s in ransomNote:
if s not in magazineCout:
return False
if s not in ransomNoteCout:
ransomNoteCout[s] = 1
else:
ransomNoteCout[s] +=1
if ransomNoteCout[s] > magazineCout[s]:
return False
return True
# 上面的那个稍微改动一下
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
ransom = dict()
magazi = dict()
if len(ransomNote) > len(magazine):
return False
for x in magazine:
if x not in magazi:
magazi[x] = 1
else:
magazi[x] += 1
for x in ransomNote:
if x not in magazi:
return False
magazi[x] -= 1
if magazi[x]<0:
return False
return True
888.公平的糖果交换
题目链接:https://leetcode.cn/problems/fair-candy-swap/
分析:
因为最终是要两个列表得总和相等,因此我们记爱丽丝和鲍勃当前的总和为alice 和bob,然后我们要从爱丽丝和鲍勃当前中取出一个分别交换给对方,取出的分别记为x , y 。
这样我们就能得到等式 Alice - x + y = bob - y + x ,所以x = (alice-bob)//2+y
class Solution:
def fairCandySwap(self, aliceSizes: List[int], bobSizes: List[int]) -> List[int]:
alice = sum(aliceSizes)
bob = sum(bobSizes)
mean = (alice-bob)//2
for y in bobSizes:
x = y + mean
if x in aliceSizes:
return [x,y]