97. 交错字符串
题解:动态规划
dp[i][j]表示s[0:i-1]与s[0:j-1]是否可以交错组成s3[0:i+j-1]
1.dp[0][0]=True
2.dp[i][0] = dp[i-1][0] && s1[i-1]==s3[i-1]
3.dp[0][j] = dp[0][j-1] && s2[j-1]==s3[j-1]
4.dp[i][j] = (dp[i-1][j] and s1[i-1]==s3[i+j-1]) or (dp[i][j-1] and s2[j-1]==s3[i+j-1])
class Solution(object):
def isInterleave(self, s1, s2, s3):
lens1 = len(s1)
lens2 = len(s2)
lens3 = len(s3)
if lens1+lens2!=lens3:
return False
dp = [[False for i in range(lens2+1)]for j in range(lens1+1)]
dp[0][0]=True
for i in range(1,lens1+1):
dp[i][0] = dp[i-1][0]==True and s1[i-1]==s3[i-1]
for j in range(1,lens2+1):
dp[0][j] = dp[0][j-1]==True and s2[j-1]==s3[j-1]
for i in range(1,lens1+1):
for j in range(1,lens2+1):
dp[i][j]=(dp[i-1][j]==True and s1[i-1]==s3[i+j-1])or (dp[i][j-1]==True and s2[j-1]==s3[i+j-1])
print(dp)
return dp[lens1][lens2]
264. 丑数 II
丑数中每个数字都可以由丑数序列u_numbers中之前的数字乘以2 3 5得到
1.用三个idx2 idx3 idx5记录分别用u_numbers中哪个数字乘以2 3 5,idx初始化为0,u_numbers初始化为[1]。
2.分别计算u_numbers[idx2]*2 u_numbers[idx3]*3 u_numbers[idx5]*5,求出三个结果中的最小值next_num,加入u_numbers中,并将对应的idx+1。
class Solution:
def nthUglyNumber(self, n: int) -> int:
idx2 = 0
idx3 = 0
idx5 = 0
u_numbers = [1]
for i in range(n-1):
number_2 = u_numbers[idx2]*2
number_3 = u_numbers[idx3]*3
number_5 = u_numbers[idx5]*5
next_num = min(number_2,number_3,number_5)
if next_num==number_2:
idx2 = idx2+1
if next_num==number_3:
idx3 = idx3+1
if next_num==number_5:
idx5 = idx5+1
u_numbers.append(next_num)
return u_numbers[-1]
剑指 Offer 34. 二叉树中和为某一值的路径
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
res = []
if not root:
return res
self.target = expectNumber
self.dfs(root, res, [root.val])
return res
def dfs(self, root, res, path):
# 和大于要求的整数,则直接换路搜索
if sum(path)>self.target:
return
if not root.left and not root.right and sum(path) == self.target:
res.append(path)
if root.left:
self.dfs(root.left, res, path + [root.left.val])
if root.right:
self.dfs(root.right, res, path + [root.right.val])
86. 分隔链表
题解:
创建两个链表,一个保存原始链表中值小于x的节点,一个保存原始链表中值大于等于x的节点,然后把后一个链表接在前一个链表之后。
1.创建两个链表smallerhead,greaterhead,一个保存原始链表中值比x小的节点,一个保存原始链表中值大于或等于x 的节点。
2.smaller=smallerhead greater=greaterhead。
3.对原始链表中每个节点进行判断,如果当前head.val<x,则smaller.next=head,同时smaller后移,否则greater.next=head,greater后移一个节点。
4.对原始链表每个节点判断完成后,将greater.next设为None,把greaterhead链表接在samller之后。
5.返回smallerhead.next。
class Solution(object):
def partition(self, head, x):
smallerhead = smaller = ListNode()
greaterhead = greater = ListNode()
while head:
if head.val<x:
smaller.next = head
smaller = smaller.next
else:
greater.next = head
greater = greater.next
head = head.next
greater.next = None
smaller.next = greaterhead.next
return smallerhead.next
395. 至少有K个重复字符的最长子串
给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
示例 1:
输入:s = “aaabb”, k = 3
输出:3
解释:最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。
示例 2:
输入:s = “ababbc”, k = 2
输出:5
解释:最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。
提示:
1 <= s.length <= 104
s 仅由小写英文字母组成
1 <= k <= 105
方法一:递归
我们来看要实现的longestSubstring函数。
它接受参数“字符串s”和“出现次数k”,返回串中字母每个都在串中出现至少k kk次的最长子串长度
首先,我们遍历字符串中出现的每一种字母。对于某种字母,如果这种字母出现次数本来就不足k kk次,那么只要是包含这种字母的子串,必定不满足题目要求。
因此,我们就可以以这种字母为分界,研究不包含这种字母的部分是否是满足题意的子串(递归)
例如aaabcccc, k = 3,我们遍历字符串aaabcccc中出现过的每一种字母a、b、c
对于字母a,其出现次数满足“最少出现3次”
对于字母b,其出现次数不满足“最少出现3次”,因此以b为分隔,递归判断各个子串是否符合要求
以b为分隔,可以将原始字符串分割成两个子串,分别是aaa和cccc,我们对这两个子串分别计算longestSubstring,最优结果即为答案
对于字符串aaa:其中只包含字母a,且a出现的次数满足“最少出现3次”。也就是说这是一个满足题意的字符串,返回答案“3”
对于字符串cccc:其中只包含字母c,且c出现的次数满足“最少出现3次”。也就是说这是一个满足题意的字符串,返回答案“4”
因此递归结束后,最佳答案是4
对于字母c,其出现次数满足“最少出现3次”
class Solution:
def longestSubstring(self, s: str, k: int) -> int:
for c in set(s):
if s.count(c) < k:
return max(self.longestSubstring(substr, k) for substr in s.split(c))
return len(s)
12. 整数转罗马数字
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例 1:
输入: 3
输出: “III”
示例 2:
输入: 4
输出: “IV”
示例 3:
输入: 9
输出: “IX”
示例 4:
输入: 58
输出: “LVIII”
解释: L = 50, V = 5, III = 3.
示例 5:
输入: 1994
输出: “MCMXCIV”
解释: M = 1000, CM = 900, XC = 90, IV = 4.
思路:
这道题和上次的罗马数字转整数刚好是相反的,但是都用到了同一个知识点,也就是Python中的字典,这里我将IV、IX等6种情况都直接在字典中写出来了,只需要通过for循环遍历字典中的每一个数,然后看哪些罗马字符能够组成给出的数。根据题目给的提示,比如num=1994,那么肯定需要一个1000,也就是M,然后剩下的字符肯定不包含M了,我们将num-1000,再看剩下的这些数由哪些字符组成,以此找到所有的字符,形成一个字符串。
class Solution:
def intToRoman(self, num: int):
dict = {'M': 1000, 'CM': 900, 'D': 500, 'CD': 400, 'C': 100, 'XC': 90, 'L': 50, 'XL': 40, 'X': 10, 'IX': 9,
'V': 5, 'IV': 4, 'I': 1}
s = ''
for i in dict:
while dict[i] <= num: # 判断当前字符需要几个
s += i
num-=dict[i]
return s
316. 去除重复字母
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
示例 1:
输入:s = “bcabc”
输出:“abc”
示例 2:
输入:s = “cbacdcbc”
输出:“acdb”
提示:
1 <= s.length <= 104
s 由小写英文字母组成
思路:
1.栈
2.比前一个字母的字母序小且后面还有重复的就弹出
class Solution:
def removeDuplicateLetters(self, s: str) -> str:
stack = []
for i, c in enumerate(s):
if c not in stack:
while c < stack[-1] and stack[-1] in s[i + 1:]:
stack.pop()
stack.append(c)
return ''.join(stack[1:])
剑指 Offer 45. 把数组排成最小的数
题解一:
思路:将nums中数字重复,取前面几位有效位进行比较。比如3和32,都重复5次33333 3232323232,32323比33333小,因此32应该放在3之前。
1.定义一个dict strnums,对nums中每个数字转为str,重复5次取前10位,按照 在原nums中的序号:前10位格式加入strnums。
2.对strnums按照key从小到大排序。
3.创建新list newnums,按照排序后的strnums中在nums的序号依次将对应数字加入newnums。
4.将newnums中数字拼接为str。
class Solution:
def minNumber(self, nums: List[int]) -> str:
strnums = {}
for i in range(len(nums)):
strnumi =str(nums[i])*5
strnumi = strnumi[0:10]
strnums[i] = strnumi
strlist = sorted(strnums.items(),key=lambda item:item[1])
newnums = []
for t in strlist:
newnums.append(str(nums[t[0]]))
result = "".join(newnums)
return result
题解二:比较a+b与b+a,从而判断a与b顺序。
class Solution:
def minNumber(self, nums: List[int]) -> str:
def sort_rule(x, y):
a, b = x + y, y + x
if a > b:
# 结果为大,返回一个正数
return 1
elif a < b:
# 结果为小,返回一个负数
return -1
else:
return 0
strs = [str(num) for num in nums]
strs.sort(key=functools.cmp_to_key(sort_rule))
return ''.join(strs)
剑指 Offer 53 - I. 在排序数组中查找数字 I
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
class Solution:
def search(self, nums: List[int], target: int) -> int:
return nums.count(target)