1、找到 a
,找到 b
,让 a + b = target
思路:将{a:b}={a:target-a} 的形式不断探寻字典
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
dic = {}
for index, num in enumerate(nums):
if num in dic:
return [dic[num], index]
dic[target - num] = index
print(dic)
if __name__ == "__main__":
nums = [2, 7, 11, 15]
target = 9
assert (Solution().twoSum(nums, target) == [0, 1])
# print(Solution().twoSum(nums, target))
# nums = [3, 2, 4]
# target = 6
# assert (Solution().twoSum(nums, target) == [1, 2])
2、两个长整数之和
思路:利用链表对整数个从位到最高位依次相加
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
head = ListNode(0)
p = head
quot = 0
while l1 or l2 or quot != 0:
if l1:
quot += l1.val
l1 = l1.next
if l2:
quot += l2.val
l2 = l2.next
quot, rem = divmod(quot, 10) #return the tuple (x//y, x%y)
print(quot,rem)
p.next = ListNode(rem)
p = p.next
return head.next
def compareLinkedList(l1, l2):
while l1 or l2:
if not (l1 and l2) or l1.val != l2.val:
return False
l1 = l1.next
l2 = l2.next
return True
if __name__ == "__main__":
l1 = ListNode(2)
l1.next = ListNode(4)
l1.next.next = ListNode(3)
l2 = ListNode(5)
l2.next = ListNode(6)
l2.next.next = ListNode(4)
lsum = ListNode(7)
lsum.next = ListNode(0)
lsum.next.next = ListNode(8)
print(compareLinkedList(Solution().addTwoNumbers(l1, l2), lsum))
3、相同数=树
思路:递归还是那个递归,门口有一颗二叉树,另一颗也是二叉树。它们长得一样不?从根开始看呗
class Tree:
def __init__(self,x):
self.val=x
self.left=None
self.right=None
class Solution:
def is_same(self,p,q):
if p and q:
return p.val==q.val and self.is_same(p.left,q.left) and self.is_same(p.right,q.right)
return p is q
if __name__ == '__main__':
example=Tree(1)
example.left=Tree(2)
example.right=Tree(3)
assert (Solution().is_same(example,example) is True)
4、没有重复字符的最长子字符串的长度。
思路:
class Solution:
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
tmp = 0
p = 0
dic = {}
for index, value in enumerate(s):
if value in dic and dic[value] >= p:
tmp = max(tmp, index - p) #tmp记录当前最长字符串,index - p 指代上一个没有重复的子字符串长度
p = dic[value] + 1
dic[value] = index
return max(tmp, len(s) - p) #针对‘abc’的情况跟
if __name__ == "__main__":
print(Solution().lengthOfLongestSubstring("abcabcbb") == 3)
print(Solution().lengthOfLongestSubstring("abba") == 2)
print(Solution().lengthOfLongestSubstring("pwwkew") == 3)
5、给一组数据,返回两组边界中可盛放水最多的一组
Input: [1,8,6,2,5,4,8,3,7] | |
Output: 49 |
上面的垂直线由数组[1,8,6,2,5,4,8,3,7]表示。在这种情况下,容器可容纳的最大水面积(蓝色部分)为49。
思路:有两个指针从两端开始走,若它们相加大于目标,那么就把右边的指针向前挪一位,反之左边的挪一位
def size(nums):
l,r=0,len(nums)-1
tmp=0
while l<r:
tmp=max(tmp,min(nums[r],nums[l])*(l-r))
if nums[r]<nums[l]:
r-=1
else:
l+=1
return tmp
6、交换糖果
Alice和Bob有不同大小的糖果棒:A [i]是Alice拥有的第i个糖果棒的大小,B [j]是Bob拥有的第j个糖果棒的大小。
由于他们是朋友,他们想交换一个糖果,以便交换后,他们都有相同的糖果总量。(一个人拥有的糖果总量是他们拥有的糖果大小的总和。)
返回一个整数数组ans,其中ans [0]是Alice必须交换的糖的大小,ans [1]是Bob必须交换的糖的大小。
输入:A = [1,1],B = [2,2]
产出:[1,2]
有两个好盆友,要交换糖果使得他们两个的糖果一样。
输出的结果也是交换的糖果数量而不是下标,所以非常容易写。
设爱丽丝给 x 颗糖,得到 y颗。那鲍勃就给 y 得到 x。
最终是
1? - x + y = 2? - y + x
2x - 2y = 1? - 2?
x - y = (1? - 2?) / 2 #其中x-y代表糖的增量
def tang(A,B):
tmp=(sum(A)-sum(B))//2
for i in A:
if i-tmp in B:
return (i,i-tmp) #代表糖的增量值恰好可以被两个数组中元素满足
二、回溯 (本质,通过递归从结果推断原因)
给定n对括号,编写一个函数来生成格式正确的括号的所有组合。
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
class Solution(object):
def generatetmp(self, n):
"""
:tlabel2pe n: int
:rtlabel2pe: List[str]
"""
result = []
def kuo(label1, label2, tmp): #这里label 代表 '('的数量 ,label2代表 ')'的数量
if not label1 and not label2:
result.append(tmp)
return
if label2 > label1:
kuo(label1, label2-1, tmp=tmp+')')
if label1: #代表,每次循环都有可能加入"(' 代表搜索空间,且设置label1为条件,由于label1在条件语句中是递减的!
#print('tmp',tmp)
kuo(label1-1, label2, tmp=tmp+'(')
kuo(n-1, n, '(')
return result
a=Solution().generatetmp(3)
print(a)
7、给定按升序排序的整数数组,找到给定目标值的起始位置和结束位置。
算法的运行时复杂度必须为O(log n)。
如果在数组中找不到目标,则返回[-1,-1]。
例1:
输入:nums = [5,7,7,8,8,10],目标= 8
产出:[3,4]
例2:
输入:nums = [5,7,7,8,8,10],目标= 6
输出:[-1,-1]
思路:改良二分法,由于要找的是两个数,因此要判断,找到target时,移动左边还是右边
class Solution(object):
def find_right(self,nums,target):
l,r=0,len(nums)
res=[]
while l<r:
mid=l+(r-l)//2
if nums[mid]==target:
res.append(mid)
if nums[mid]>target:
r=mid
else: # 用【1,2,2,2,6】为例子,相等时,移动左边指针,判断mid右边是否还有target,有的话加入列表,最后列表返回最后一个元素
l=mid+1
print('right',res)
return res[-1] if res else -1
def find_left(self,nums,target):
l,r=0,len(nums)
res=[]
while l<r:
mid=l+(r-l)//2
if nums[mid]==target:
res.append(mid)
if nums[mid]<target:
l=mid+1
else: # 用【1,2,2,2,6】为例子,相等时,移动右边指针
r=mid
print('left',res)
return res[-1] if res else -1
def find_target(self,nums,target):
left=self.find_left(nums,target)
print('11111111111')
if left==-1:
return [-1,-1]
return [left,self.find_right(nums,target)]
a=[5,7,7,8,8,10]
b=Solution().find_target(a,8)
print(b)
8、假设按升序排序的数组在事先未知的某个枢轴处旋转。
(即[0,1,2,4,5,6,7]可能变为[4,5,6,7,0,1,2])。
找到最小元素。
您可以假设数组中不存在重复。
例1:
输入:[3,4,5,1,2]
输出:1
例2:
输入:[4,5,6,7,0,1,2]
输出:0
思路:找到旋转点,旋转点即比列表中第一个元素更小的数 ,二分法目标为首元素
class Solution:
def find_rotate(self,nums):
l = 1
r = len(nums)
count=0
target=nums[0]
while l <r:
count+=1
mid =l+(r-l) // 2
if nums[mid] > target: #此处重点,和二分法不同
l =mid+1
else:
r =mid
return nums[l]
def find_min(self,nums):
index=self.find_rotate(nums)
if index>=len(nums):
return nums[0]
return nums[index]
a=Solution().find_rotate([5,6,7,8,9,10,2,3])
print(a)
思路:峰值应比较相邻的值,二分法目标为相邻值
def find_max(nums):
l,r=0,len(nums)
#target=nums[0]
while l<r:
mid=l+(r-l)//2
if nums[mid]<nums[mid+1]:
l=mid+1
else:
r=mid
return nums[l]
a=[6,10,8,7]
b=find_max(a)
print(b)
9、Find the minimum element.
Input: [2,2,2,0,1]
Output: 0
class Solution:
def find_rotate(self,nums):
tmp=nums[0]
index=0
for i in nums:
if i==tmp:
index+=1
lp=index
rp=len(nums)
while lp<rp:
mid=lp+(rp-lp)//2
if nums[mid]>tmp:
lp=mid+1
else:
rp=mid
return lp
def find_min(self,nums):
a=self.find_rotate(nums)
if a==len(nums):
return nums[0]
return nums[a]
if __name__ == '__main__':
a=Solution().find_min([2,3,4,5,6,1])
print(a)
10、球场C 可容纳 M*N个球迷。统计有几组球迷群体:
1. 每组球迷群体会选择相邻的作为(8个方位。)
2. 不同球迷群体不会相邻。
3. 给一个 M*N 的二维球场,0为没人,1为有人,求出群体个数P以及最大的群体人数Q.
test = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
]
# 6 8
def makeAroundXY(x, y):
# ((x, y)....)
return ((x, y-1),
(x, y+1),
(x-1, y),
(x+1, y),
(x-1, y-1),
(x-1, y+1),
(x+1, y+1),
(x+1, y-1))
def getFootballFans(nums):
"""
[[0, 0, 0].....]
从 0,0 开始,如果遇到1则进入递归:
递归结束条件:
四周都是 0或边界。
结束时将搜索到的人数添加。
未结束时根据四周的情况进入相同的递归。
"""
fans_groups = []
x = 0
y = 0
y_label = len(nums[0])
x_label = len(nums)
def fans(x, y, count=0):
# nonlocal nums
Xy = makeAroundXY(x, y)
for i in Xy:
try:
if i[0] < 0 or i[1] < 0: #边界
continue
if nums[i[0]][i[1]] == 1:
nums[i[0]][i[1]] = 0
count += 1
t = fans(i[0], i[1], 0)
count += t
except IndexError:
continue
return count
for x in range(x_label):
for y in range(y_label):
if nums[x][y] == 1:
nums[x][y] = 0
fans_groups.append(fans(x, y, 1))
if not fans_groups:
return (0, 0)
return (len(fans_groups), max(fans_groups))
a=getFootballFans(test)
print(a)
11、给定二叉树,找到树的最后一行中最左边的值。
例1:
输入:
2
/ \
1 3
输出: 1
例2:
输入:
1
/ \
2 3
/ / \
4 5 6
/
7
输出: 7
思想: 广度优先,从右向左,弹出最后一个
class Solution(object):
def findBottomLeftValue(self, root):
"""
:type root: TreeNode
:rtype: int
"""
queue = [root]
res = [] #之所以指定新列表是由于,queue列表会弹出一个数的同时添加两个数,造成死循环
result = root.val
while 1:
while queue:
node = queue.pop()
if node.right:
res.append(node.right)
result = node.right.val
if node.left:
res.append(node.left)
result = node.left.val
if not res:
return result
queue.extend(res[::-1]) #列表添加列表的方法,变为【left,right】 pop()先弹出right
res = []
12、分水果
在一排树中,第i棵树产生具有树型[i]的果实。
从任意树开始,然后重复执行以下步骤:
1.将这棵树上的一片水果加到你的篮子里。如果你不能,停下来。
2.移动到当前树右侧的下一个树。如果右边没有树,请停止。
请注意,在初始选择起始树后,您没有任何选择:您必须执行步骤1,然后执行步骤2,然后返回步骤1,然后执行步骤2,依此类推,直至停止。
你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子每个只携带一种水果。
您可以使用此程序收集的水果总量是多少?
例1:
输入:[1,2,1]
输出:3
说明:我们可以收集[1,2,1]。
例2:
输入:[0,1,2,2]
输出:3
说明:我们可以收集[1,2,2]。
如果我们从第一棵树开始,我们只会收集[0,1]。
例3:
输入:[1,2,3,2,2]
产量:4
说明:我们可以收集[2,3,2,2]。
如果我们从第一棵树开始,我们只会收集[1,2]。
例4:
输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
说明:我们可以收集[1,2,1,1,2]。
如果我们从第一棵树或第八棵树开始,我们只会收集4个水果。
对于每一个i,都会产生tree [i]类型的水果。有两个篮子,每个篮子只能放一种类型,但同类型的不限次数。
问最多能摘的水果数量。
转换数学思想 : 从一个列表中选取连续重复子列表最大长度(子列表为2个数字重复)
class Solution:
# def tongji(self,res,i): #自己写个计数器
# if i not in res:
# res[i]=1
# else:
# res[i]+=1
# return res
def totalFruit(self, nums):
dic={}
count, res = 0, 0
print(dic)
for i in range(len(nums)):
dic[nums[i]]=dic[nums[i]]+1 if nums[i] in dic else 1
print(dic)
while len(dic) > 2:
dic[nums[count]] -= 1
if not dic[nums[count]]:
dic.pop(nums[count])
count += 1 #count统计字典中第一个元素出现次数
# print('dic_last',dic)
# print('l',count)
# print('nums[l]',nums[count])
res = max(res, i - count + 1) # i-count 总元素出现次数-第一个元素出现次数 , 由于i从0开始所以+1
return res
a=Solution().totalFruit([0,1,2,2])
print(a)
12、三元递增
如果存在i,j,k则返回true
这样arr [i] <arr [j] <arr [k]给定0≤i<j <k≤n-1否则返回false。
注意:您的算法应该以O(n)时间复杂度和O(1)空间复杂度运行。
例1:
输入:[1,2,3,4,5]
输出:true
例2:
输入:[5,4,3,2,1]
输出:false
给一个数组,若里面存在arr [i] <arr [j] <arr [k]且0 <= i <j <k <= n-1,则返回True。
否则假。
nums=[5,4,3,2,1]
def ok(nums):
once=False
tmp=nums[0]
for i in range(1,len(nums)):
if once ==False and tmp<nums[i]:
once=True
tmp=nums[i]
continue
if once==True and tmp<nums[i]:
return True
return False
print(ok(nums))
12、最大岛屿面积
给定0和1的非空二维阵列网格,岛是一组1(表示陆地)4方向连接(水平或垂直)。您可以假设网格的所有四个边缘都被水包围。
找到给定2D阵列中岛的最大面积。(如果没有岛,则最大面积为0.)
例1:
[[0,0,1,0,0,0,0,1,0,0,0,0,0]
[0,0,0,0,0,0,0,1,1,1,0,0,0]
[0,1,1,0,1,0,0,0,0,0,0,0,0]
[0,1,0,0,1,1,0,0,1,0,1,0,0]
[0,1,0,0,1,1,0,0,1,1,1,0,0]
[0,0,0,0,0,0,0,0,0,0,1,0,0]
[0,0,0,0,0,0,0,1,1,1,0,0,0]
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
给出上面的网格,返回6.注意答案不是11,因为岛必须是4向连接。
例2:
[[0,0,0,0,0,0,0,0]]
给定上面的网格,返回0。
注意:给定网格中每个维度的长度不超过50。
class Solution():
def find4(self,x,y):
return ((x+1,y),
(x-1,y),
(x,y+1),
(x,y-1))
def find_max(self,nums):
y_label=len(nums[0])
x_label=len(nums)
res=[]
def find_point(x,y,count=0):
maybe=self.find4(x,y)
for tmp in maybe:
try:
if tmp[0]<0 or tmp[1]<0:
continue
if nums[tmp[0]][tmp[1]]==1:
nums[tmp[0]][tmp[1]]=0
count+=1
t=find_point(tmp[0],tmp[1],count=0)
count+=t
except IndexError:
break
return count
for i in range(x_label):
for j in range(y_label):
if nums[i][j]==1:
nums[i][j]=0
res.append(find_point(i,j,count=1))
return max(res)
test = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0, 1, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
]
s=Solution().find_max(test)
print(s)
13、插入间隔
给定一组非重叠间隔,在间隔中插入新间隔(必要时合并)。
您可以假设间隔最初是根据其开始时间排序的。
例1:
输入:interval = [[1,3],[6,9]],newInterval = [2,5]
产出:[[1,5],[6,9]]
例2:
输入:interval = [[1,2],[3,5],[6,7],[8,10],[12,16]],newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
说明:因为新区间[4,8]与[3,5],[6,7],[8,10]重叠。
class Solution(object):
def insert(self, nums, new_nums):
"""
:type intervals: List[Interval]
:type new_nums: Interval
:rtype: List[Interval]
"""
nums.append(new_nums)
nums = sorted(nums, key=lambda x: x[0])
if not nums:
return []
result = []
head = nums[0][0]
tail = nums[0][1]
for x in range(1, len(nums)):
i = nums[x]
if tail >= i[0]:
tail = max(tail, i[1])
else:
result.append([head, tail]) #若区间不相交,则加入
head = i[0]
tail = i[1]
result.append([head, tail])
return result
a=Solution().insert([[1,2],[3,5],[6,7],[8,10],[12,16]],[4, 8])
print(a)
14、能组合成最大数
给定一个非负整数列表,将它们排列成最大数字。
例1:
输入:[10,2]
输出:“210”
例2:
输入:[3,30,34,5,9]
输出:“9534330”
注意:结果可能非常大,因此您需要返回一个字符串而不是整数。
class Solution(object):
def largestNumber(self, nums):
if not any(nums):
return '0'
print(any(nums))
max_nums = len(str(max(nums)))
def makeEqual(s, length=max_nums):
if len(s) == length:
return s
s=int(s)
while length-1>0:
length-=1
s+=s*10
return str(s)
# 这种补位会通过测试,但是 Leetcode 的测试并没有包含所有的情况。
# x = max(s) * (length - len(s)) #将[3,5,9] 补位为33,55,99
# print(s+x)
# return s+x
return ''.join(sorted(map(str, nums), key=makeEqual, reverse=True)) #map(str, nums)每个int型str化
a=Solution().largestNumber([3,30,34,5,9])
print(a)
14、最长连续子序列
Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
class Solution:
def max_length(self,nums):
count=0
nums_set=set(nums)
for i in nums:
if i-1 not in nums_set: #使得该值一定是某个连续数字的最小数
tmp=1
x=i
while True:
if x+1 in nums_set:
tmp+=1
x+=1
else:
count=max(count,tmp) #用tmp统计子域,count统计全部域
break
return count
a=Solution().max_length([1,2,3,4,100])
print(a)
15、最大连续子数组之积
给定整数数组nums,找到具有最大乘积的数组(包含至少一个数字)内的连续子数组。
例1:
输入:[2,3,-2,4]
产量:6
说明:[2,3]具有最大的产品6。
例2:
输入:[ - 2,0,-1]
输出:0
说明:结果不能为2,因为[-2,-1]不是子数组。
思路:由于是乘法(存在负数)计算,因此最大,最小值之间是可以相互置换的。因此,要同事保存每次的最大,最小值,方便下次计算
绝对值最大的数,不是最大就是最小
class Solution:
def find_max(self,nums):
max_value=nums[0] #假设初始值最大
last_max_min=[[max_value]] #用来记录每一次的最大最小值
for i in range(1,len(nums)):
max_min=[nums[i]*j for j in last_max_min[-1]] #用当前最大,最小值与每个元素相乘 得到当前最大,最小值
tmp_max=max(nums[i],max(max_min)) #当前最大最小值与当前值比较
tmp_min=min(nums[i],min(max_min))
last_max_min.append([tmp_max,tmp_min])
max_value=max(max_value,tmp_max) #记录历史最大值
return max_value
a=Solution().find_max([2,3,-2,4])
print(a)
17、最大连续子数组之和
“””
给定整数数组nums,找到具有最大总和并返回其总和的连续子数组(包含至少一个数字)。
例:
输入:[ - 2,1,-3,4,-1,2,1,-5,4],
产量:6
说明:[4,-1,2,1]具有最大的和= 6。
class Solution:
def find_max(self,nums):
tmp=nums[0] #假设初始值最大
max_value=nums[0]
for i in nums[1:]:
tmp=max(i,i+tmp) #当前时刻与历史总时刻比较
print(tmp)
max_value=max(max_value,tmp) #max_value记录上一次最大值
return max_value
a=Solution().find_max([2,3,-2,4])
print(a)
18、给定n个整数的数组,其中n> 1,返回一个数组输出,使得output [i]等于除nums [i]之外的所有nums元素的乘积。
例:
输入:[1,2,3,4]
产量:[24,12,8,6]
注意:请在没有除法的情况下解决,并在O(n)中解决。
思路:
A[0]=1,A[1]=2,A[2]=2*3=6,A[3]=2*3*4=24;
B[0]=3*4*5=60,B[1]=4*5=20,B[2]=5,B[3]=1;
result[0]=A[0]*B[0],result[1]=A[1]*B[1];
class Solution(object):
def productExceptSelf(self, nums):
left = [1]
right = [1]
for i in range(len(nums)-1):
left.append(left[-1] * nums[i]) #[1,2,2*3,2*3*4]
for i in range(len(nums)-1, 0, -1):
right.append(right[-1] * nums[i]) #[1,5,20,60]
length = len(left)
return [left[i] * right[length-1-i] for i in range(length)] # [1*24,1*12,2*4,1*6]
19、链表删除尾部第n个节点
1->2->3->4->5, and n = 2.
1->2->3->5.
class Solution(object):
def removeNthFromEnd(self, head, n):
"""
:type head: ListNode
:type n: int
:rtype: ListNode
"""
q = p = head
for i in range(n):
q = q.next
if not q:
return head.next
while q.next:
q = q.next
p = p.next
p.next = p.next.next
return head
一个被旋转的数组,例如[0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
思路: 先找到旋转点,后判断目标所处的区域,然后用二分搜索
class Solution(object):
def find_rotate(self,nums):
tmp=nums[0]
l,r=0,len(nums)
while l<r:
mid=l+(r-l)//2
if nums[mid]>tmp:
l=mid+1
else:
r=mid
return r
def bi_serch(self,nums,target,l,r):
while l<r:
mid=l+(r-l)//2
if nums[mid]==target:
return mid
if nums[mid]<target:
l=mid+1
else:
r=mid
return -1
def serarch(self,nums,target):
if target==nums[0]:
return 0
if target<nums[0]:
l=self.find_rotate(nums)
r=len(nums)
else:
l=0
r=self.find_rotate(nums)
return self.bi_serch(nums,target,l,r)
nums = [4,5,6,7,0,1,2]
target = 1
b=Solution().serarch(nums,target)
print(b)
21、落单的数
给定一个非空的整数数组,除了一个元素外,每个元素都会出现两次。找一个单一的。
输入:[2,2,1]
输出:1
例2:
输入:[4,1,2,1,2]
产量:4
线性时间内,且不用额外空间。
思路:利用‘与’运算
class Solution(object):
def find_one(self,nums):
tmp=nums[0]
for i in nums[1:]:
tmp^=i
return tmp
nums = [4,4,5,5,2,3,3]
target = 1
b=Solution().find_one(nums)
print(b)
21、给定一个非负整数数组A,返回一个由A的所有偶数元素组成的数组,后跟A的所有奇数元素。
输入:[3,1,2,4]
产出:[2,4,3,1]
产出[4,2,3,1],[2,4,1,3]和[4,2,1,3]也将被接受
思路:空列表,偶数加前面,奇数加后面
class Solution(object):
def even_odd(self,nums):
res=[]
for i in nums:
if i%2==0:
res=[i]+res
else:
res=res+[i]
return res
nums = [4,4,5,5,2,3,3]
b=Solution().even_odd(nums)
print(b)
22、列表所有子列表的最小值和
给定一个整数数组A,找到min(B)的总和,其中B的范围超过A的每个(连续)子数组。
由于答案可能很大,因此返回模10 ^ 9 + 7的答案。
例1:
输入:[3,1,2,4]
产量:17
说明:子阵列是[3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2] ,4],[3,1,2,4]。
最小值为3,1,2,4,1,1,2,1,1,1。总和为17。
思路: 统计当前数为最小数的列表长度。
对于A
中的每一个值A[i]
,寻找以它为最小值的子序列的数量。也就是说,我们需要寻找A[i]
左侧第一个比它大的值的位置,以及右侧第一个比它大的值的位置。然后就可以计算对应的子序列的数量了。
class Solution(object):
def sumSubarrayMins(self, A):
"""
:type A: List[int]
:rtype: int
"""
mod = 10**9 + 7
# count
left = []
right = []
# (num, count)
tmp_left = []
tmp_right = []
for i in A: #统计当前数为最小值的左区间长
count = 1
while tmp_left:
if i < tmp_left[-1][0]:
count += tmp_left[-1][1]
tmp_left.pop()
else:
break
tmp_left.append((i, count))
print('tmp_left',tmp_left)
left.append(count)
print(left)
for i in reversed(A): #统计当前数为最小值的右区间长,右小等会翻转左小
count = 1
while tmp_right:
if i <= tmp_right[-1][0]:
count += tmp_right[-1][1]
tmp_right.pop()
else:
break
tmp_right.append((i, count))
right.append(count)
right.reverse()
print(right)
result = 0
for i in range(len(A)):
print(A[i] * left[i] * right[i]) #当前值* 以当前值为最小值的区间个数
result += A[i] * left[i] * right[i]
return result % mod
Solution().sumSubarrayMins([3,1,2,4])
23、螺旋遍历一个矩阵
Input:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
Output: [1,2,3,6,9,8,7,4,5]
Example 2:
Input:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]
思路:
0, 0开始走,
right -> down,
down -> left,
left -> up,
up -> right.
每走过一点,将值添加到结果中,走过的点记为 'x'。当四周都是 'x' 或边界时结束。
def checkStop(matrix, x, y):
t = [(x+1, y),
(x-1, y),
(x, y+1),
(x, y-1),
(x, y)]
for i in t:
try:
if i[1] < 0 or i[0] < 0:
continue
if matrix[i[1]][i[0]] != 'x':
return False
except IndexError:
continue
else:
return True
class Solution(object):
def right(self, matrix, x, y, result, stop):
if checkStop(matrix, x, y):
return result
while 1:
try:
# matrix
if matrix[x][y]== 'x':
raise IndexError
result.append(matrix[x][y])
matrix[x][y] = 'x'
y += 1
except IndexError:
y -= 1
return self.down(matrix, x+1, y, result, stop)
def down(self, matrix, x ,y, result, stop):
if checkStop(matrix, x, y):
return result
while 1:
try:
# matrix
if matrix[x][y] == 'x':
raise IndexError
result.append(matrix[x][y])
matrix[x][y] = 'x'
x += 1
except IndexError:
x -= 1
return self.left(matrix, x, y-1, result, stop)
def left(self, matrix, x, y, result, stop):
if checkStop(matrix, x, y):
return result
while 1:
try:
# matrix
if matrix[x][y] == 'x' or x < 0:
raise IndexError
result.append(matrix[x][y])
matrix[x][y] = 'x'
y -= 1
except IndexError:
y += 1
return self.up(matrix, x-1, y, result, stop)
def up(self, matrix, x, y, result, stop):
if checkStop(matrix, x, y):
return result
while 1:
try:
# matrix
if matrix[x][y] == 'x' or y < 0:
raise IndexError
result.append(matrix[x][y])
matrix[x][y] = 'x'
x -= 1
except IndexError:
x += 1
return self.right(matrix, x, y+1, result, stop)
def spiralOrder(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[int]
"""
x, y = 0, 0
result = []
# right -> down
# down -> left
# left -> up
# up -> right
stop = {}
return self.right(matrix, 0, 0, result, stop)
a=Solution().spiralOrder([
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
])
print(a)
23、两链表之和
Input: (6 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 6 -> 8 -> 0 -> 7
思路: 若用栈的方式,要占用额外空间,因此考虑用字符串来存储值
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
num1 = ""
num2 = ""
# loop through the first linked list, storing the values in the num1 variable
while l1 is not None:
num1 += str(l1.val)
l1 = l1.next
# follows same process as above
while l2 is not None:
num2 += str(l2.val)
l2 = l2.next
# calculate the sum of the values that we just obtained and store it as a string
summation = str(int(num1) + int(num2))
# make the head of the node the first number in the summation string
head = ListNode(summation[0])
# create a new reference to the head so we can manipulate the linked list but not lose the original reference to the head
temp = head
# loop through the remaining numbers in the summation string, each time creating a new node
for val in summation[1:]:
temp.next = ListNode(val)
temp = temp.next
# return the original reference to the head
return head
24、链表xiang节点
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
begin to intersect at node c1.
class Node:
def __init__(self,x):
self.next=None
self.val=x
class Solution:
def find_similar_node(self,l1,l2):
p=l1
q=l2
if not p or not q:
return None
while p!=q:
if p==None:
return l2
if q==None:
return l1
q=q.next
p=p.next
return p
26、链表中第K大元素
27、第K大的数
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note:
You may assume k is always valid, 1 ≤ k ≤ array's length.
class Solution:
# @param {integer[]} nums
# @param {integer} k
# @return {integer}
def findKthLargest(self, nums, k):
tmp=nums[0]
large=[v for v in nums if v>tmp]
small=[m for m in nums if m<tmp]
equal=[n for n in nums if n==tmp]
if len(large)>=k: #最大第K个数,所以从最大检索
return self.findKthLargest(large,k)
if k-len(large)<=len(equal):
return equal[0]
return self.findKthLargest(small,k)
a=Solution().findKthLargest([3,2,3,1,2,4,5,5,6] ,4)
print(a)
28、八皇后问题
在一个8*8
棋盘上,每一行放置一个皇后旗子,且它们不冲突。冲突定义:同一列不能有两个皇后,每一个对角线也不能有两个皇后。当然,三个皇后也是不行的,四个也是不行的
import random
#随机模块
def conflict(state,col):
#冲突函数,row为行,col为列
row=len(state) #目前没冲突列表的长度row
for i in range(row):
if abs(state[i]-col) in (0,row-i):#重要语句 ,.如果row+1行皇后所在的列col与其他行皇后的列相同或处于对角线,则冲突
#col 代表当前时刻皇后所在列数,state[i]代表历史时刻皇后所在列数,abs(state[i]-col)为列数差,当abs(state[i]-col)==0:乃是同列 当abs(state[i]-col)《行数差,表示同对角线
# row表示当前时刻已经迭代次数(行数),row-i 表示当前行和元祖某行的行数差距(由于,不在同列或对角线要求为,当前皇后所在一定不是
#例:第一行与第二行,列数差在(0,1)间,一定是同列或者同对角线
return True
return False
def queens(num=8,state=()): #迭代器的元素放在元组中,意味不可变
#生成器函数
for pos in range(num):
if not conflict(state, pos):
if len(state)==num-1: #到达最后一行
# print('pos',pos)
yield(pos,) #(0, 4, 7, 5, 2, 6, 1, 3) 中的(3,)
else:
tmp=queens(num,state+(pos,)) #递归,结束条件,是从最后一行向一行跑,
for result in tmp: #从结果返回
print('result',result)
yield (pos,)+result #进入下一行,迭代器的递归
# def queenprint(solution):
# #打印函数
# def line(pos,length=len(solution)):
# return '. '*(pos)+'X '+'. '*(length-pos-1)
# for pos in solution:
# print (line(pos))
for solution in queens(8):
print(solution)
print (' total number is '+str(len(list(queens())))) #迭代器中元祖长度
print (' one of the range is:\n')
#queenprint(random.choice(list(queens())))
29、链表环
判断一个链表是否为一个链表环
思路: 快慢法
class Solution(object):
def hasCycle(self, head):
if not head:
return False
two_head = head.next
if not two_head:
return False
while head and two_head:
if head == two_head:
return True
head = head.next
try:
two_head = two_head.next.next #这样写时间上小号更少
except:
return False
return False
30、增高天际线
输入: grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]]
输出: 35
解释:
The grid is:
[ [3, 0, 8, 4],
[2, 4, 5, 7],
[9, 2, 6, 3],
[0, 3, 1, 0] ]
从数组竖直方向(即顶部,底部)看“天际线”是:[9, 4, 8, 7]
从水平水平方向(即左侧,右侧)看“天际线”是:[8, 7, 9, 3]
在不影响天际线的情况下对建筑物进行增高后,新数组如下:
gridNew = [ [8, 4, 8, 7],
[7, 4, 7, 7],
[9, 4, 8, 7],
[3, 3, 3, 3] ]
思路: 得到的新数组中每个元素,为原来行最大值和列最大值中的较小的一个
class Solution(object):
def maxIncreaseKeepingSkyline(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
length = len(grid[0])
# Get line max.
line_dict = {str(index):max(data) for index, data in enumerate(grid)}
print(line_dict)
# Get column max.
column_dict = {str(index):max((grid[index2][index] for index2 in range(len(grid)))) for index in range(length)}
print(column_dict)
total_increases = 0
for index, line in enumerate(grid):
for index2, cell in enumerate(line): #cell为当前点的值,min([line_dict[str(index)], column_dict[str(index2)]])为改变后的值
total_increases += min([line_dict[str(index)], column_dict[str(index2)]]) - cell
return total_increases
a=Solution().maxIncreaseKeepingSkyline([[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]])
31、两个排序后数组的中位数
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
思路:每次丢弃k//2 个最小元素,将前k-1个元素去掉
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
k = len(nums1) + len(nums2)
if k <= 2:
return sum(nums1+nums2) / k
raw_k = k
k = k // 2
print(k)
if raw_k % 2 != 0: #列表长为奇数时,返回中间索引+1(由于是向下取整 )
k += 1
while k > 1: #由于循环每次 k=k-k//2 ,k最小为1 ,若玄幻条件 k>0 ,会进入死循环
print('k',k)
tmp = k // 2
if nums1:
if tmp > len(nums1):
tmp = len(nums1)
if nums2:
if tmp > len(nums2):
tmp = len(nums2)
nums1_k_value = nums1[tmp-1] if nums1 else float('inf')#返回两个列表第k//2值小
print('nums1_k_value',nums1_k_value)
nums2_k_value = nums2[tmp-1] if nums2 else float('inf')
if nums1_k_value < nums2_k_value: #两个列表谁的第k//2位置上的值小,对那个数组进行操作
nums1 = nums1[tmp:]
else:
nums2 = nums2[tmp:]
print(nums1,nums2)
k -= tmp
result = sorted(nums1[:2] + nums2[:2])
if raw_k % 2 != 0:
return result[0]
return sum(result[:2]) / 2
a=Solution().findMedianSortedArrays([1, 2, 4, 6,8],[3, 5, 7, 9])
print(a)
32、未排序数组中第k个大的数
Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:
Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note:
You may assume k is always valid, 1 ≤ k ≤ array's length.
思路:利用快排
class Solution:
def findKthLargest(self, nums, k):
low = 0
high = len(nums) - 1
return self.Quicksort(nums, low, high, k)
def Quicksort(self, nums, low, high, k):
if low > high:
return -1
mid = self.partition(nums, low, high)
if mid == k - 1:
return nums[mid]
elif mid < k - 1:
return self.Quicksort(nums, mid + 1, high, k)
else:
return self.Quicksort(nums, low, mid - 1, k)
#self.Quicksort(nums, mid + 1, high, k)
#self.Quicksort(nums, low, mid - 1, k)
#return -1
def partition(self, nums, low, high):
left = low
right = high
key = nums[high]
while left < right: #复杂度高
while left < right and nums[left] >= key : #最好以右边开始
left += 1
while left < right and nums[right] <= key:
right -= 1
if left < right:
nums[left], nums[right] = nums[right], nums[left]
nums[right], nums[high] = nums[high], nums[right]
return right
a=Solution().findKthLargest(nums=[3,2,3,1,2,4,5,5,6],k=2)
print(a)
33、合并两个排序过的列表
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
思路:利用双指针
class Solution:
def find_mid(self,list1,list2):
p=q=Node(0)
while list1 and list2:
if list1.val<list2.val:
p.next=list1
list1=list1.next
else:
p.next=list2
list2=list2.next
p=p.next
if list1:
p.next=list1
if list2:
p.next=list2
return q.next
34、合并排序的数组
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
合并两个排序过的整数数组。
思路:利用已知的m+n一定为最后输出列表的长度
class Solution:
def merge(self,nums1,nums2,m,n):
while m>0 and n>0:
if nums1[m-1]>nums2[n-1]: #m-1 ,n-1是由于list长未(0,len(list)-1)
nums1[m+n-1]=nums1[m-1]
m-=1
else:
nums1[m+n-1]=nums2[n-1]
n-=1
print(nums1)
if m>0:
nums1[m+n-1]=nums1[m-1]
if n>0:
nums1[m+n-1]=nums2[n-1]
return nums1
a=Solution().merge( [1,2,3,0,0,0], [2,5,6],3,3)
print(a)
假设Andy和Doris想要选择一家餐馆吃晚餐,他们都有一个最受欢迎的餐馆列表。
你需要用最少的列表索引总和帮助他们找出他们的共同兴趣。
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
Output: ["Shogun"]
Explanation: The only restaurant they both like is "Shogun".
Example 2:
Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
Output: ["Shogun"]
Explanation: 索引总和最小
class Solution:
def findRestaurant(self, list1, list2):
list1_dict = {value:index for index, value in enumerate(list1)}
res_dict = {}
for index, value in enumerate(list2):
if value in list1_dict:
# print(list1_dict[value])
#print(list1_dict.get(value))
res_dict[index+list1_dict[value]]=value
return res_dict[min(res_dict)]
a=["Shogun", "Tapioca Express", "Burger King", "KFC"]
b=["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
c=print(Solution().findRestaurant(a,b))
36、2D矩阵搜索
Input:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3
Output: true
Example 2:
Input:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13
Output: false
思路: 利用两个二分查找 定位行 后再定位列,耗时最少
class Solution(object):
def binarySearch(self, rawList, target, index=0): #二分法定位target所在区间
if target >= rawList[-1]:
return len(rawList) - 1
if target < rawList[0]:
return -1
split = len(rawList) // 2
leftList = rawList[:split]
rightList = rawList[split:]
if leftList[-1] <= target and rightList[0] > target:
return len(leftList) + index - 1
if rightList[0] == target:
return len(leftList) + index
if leftList[-1] > target:
return self.binarySearch(leftList, target, index=index)
if rightList[0] < target:
return self.binarySearch(rightList, target, index=index+len(leftList))
def binarySearch2(self, rawList, target): #查找二分法
low=0
high=len(rawList)
while low<high:
mid=low+(high-low)//2
if rawList[mid]==target:
return True
if target>rawList[mid]:
low=mid+1
else:
high=mid
return False
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not any(matrix):
return False
column = [i[0] for i in matrix]
print(column)
column_result = self.binarySearch(column, target)
if column_result == -1:
return False
return self.binarySearch2(matrix[column_result], target)
a=Solution().searchMatrix(matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
],target = 3)
print(a)
37、多重三数相加
class Solution(object):
def threeSumMulti(self, A, target):
mod=10**9+7
res=0
a=A
d={}
for i in a:
if i in d:
d[i]+=1
else:
d[i]=1
print('d',d)
for i in d:
# print(i)
for j in d:
if i==j or target-i-j==i or target-i-j==j or target-i-j not in d:
print('i','j',i,j)
continue
res+=d[i]*d[j]*d[target-i-j] #满足条件的三个数都不同
print('res',res)
res//=6 #每个数字都循环了两次,每个满足条件的数字对应3个数,因此除以6 去掉重复
# print(res)
for i in d:
if d[i]<2 or target-i-i==i or target-i-i not in d:
continue
res+=(d[i]*(d[i]-1)//2)*d[target-i-i] #满足条件的两个数不同
# print(res)
for i in d:
if d[i]<3 or target!=i*3:
continue
res+=d[i]*(d[i]-1)*(d[i]-2)//6 #一个数即可满足条件
return res%mod
s=Solution()
print(s.threeSumMulti(A = [1,1,2,2,3,3,4,4,5,5], target = 8))
38、二叉树最大深度
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its depth = 3.
找到二叉树的最大深度。
class Solution(object):
def max_deep(self,root):
return max(self.max_deep(root.left),self.max_deep(root.right))+1 if root else 0
或者:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if root:
t=self.maxDepth(root.left)+1
m=self.maxDepth(root.right)+1
return max(t,m)
else:
return 0
39、给定n个整数的数组nums,是否有元素a,b,c在nums中,a + b + c = 0?找到数组中所有唯一的三元组,它们的总和为零。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
dic={} #统计重复
for index in nums:
if index in dic:
dic[index]+=1
else:
dic[index]=1
nums = sorted(set(nums))
print('nums',nums)
res = []
for i, data in enumerate(nums): #当不重复时 将满足结果的元素保存在新列表中
if data > 0:
break
target = - data
start = i + 1
end = len(nums) - 1
while start < end:
if nums[start] + nums[end] == target:
res.append([nums[start], nums[end], data])
end -= 1
start += 1
continue
if nums[start] + nums[end] > target:
end -= 1
else:
start+=1
if 0 in dic and dic[0]>=3: #3个重复元素为0时
res.append([0,0,0])
for j in dic.keys(): #2个重复元素不为0时
if j!=0 and dic[j]>=2 and -2*j in dic:
res.append([j,j,-2*j])
return res
40、最大利润
Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Example 2:
Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
class Solution(object):
def maxProfit(self, nums):
profit=0
state=0
buy=0
for i in range(len(nums)-1):
if nums[i+1]>nums[i] and state==0:
buy=nums[i]
state=1
if nums[i]>nums[i+1] and state==1:
profit+=nums[i]-buy
state=0
if state==1:
profit+=(nums[-1]-buy)
if state==0 and buy==0:
return 0
return profit
a= [7,1,5,3,6,4]
b=Solution().maxProfit(a)
print(b)
40、子集(回溯)
Example:
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
直接上递归,每条线都有两个决策:
1. 加上。
2. 不加。
class Solution(object):
def subsets(self, nums):
result = []
def maybe(i, state):
if i == len(nums):
return
result.append(state+[nums[i]])
maybe(i+1, state+[nums[i]]) #横向递归 ,当i+1==len(nums)返回,有[[1], [1, 2], [1, 2, 3]]
maybe(i+1, state) #纵向递归 i=2时,将子集加入列表(通过state)
maybe(0, [])
return result+[[]]
a=Solution().subsets([1,2,3])
print(a)
nums = [1,2,3]
a=Solution().subsets(nums)
print(a)
41、二进制子数组和
在0和1的数组A中,有多少非空子数组具有和S?
Example 1:
Input: A = [1,0,1,0,1], S = 2
Output: 4
Explanation:
The 4 subarrays are bolded below:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
Note:
A.length <= 30000
0 <= S <= A.length
A[i] is either 0 or 1.
思想: 用字典统计历史累和情况,当目标值与累和差在历史统计字典中时,表示,去掉该历史,亦满足
class Solution(object):
def count_includ(self,nums,S):
dic={0:1}
res=0
sum=0
for value in nums:
sum+=value
res+=dic[sum-S] if sum-S in dic else 0#当历史累和大于等于S 时,会有其个数中可能,思想: 当累和与S差值1时,历史统计共有2个1,则表示共有两种情况将1 去掉后,其差为0,满足条件
#等于时 1 、 [1,0,1] 2、[1,0,1,0] 大于时 1、[0,1,0,1] 2、[1,0,1]
dic[sum]=dic[sum]+1 if sum in dic else 1
print(dic)
return res
a=Solution().count_includ([1,0,1,0,1], S = 2)
print(a)
42、加油站
沿着环形路线有N个加油站,其中站i的气体量是气体[i]。
你有一辆带有无限油箱的汽车,从车站i到下一站(i + 1)需要花费成本[i]。您可以在其中一个加油站开始使用空罐。
如果您可以顺时针方向绕电路一次返回起始加油站的索引,否则返回-1。
输入:
气体= [1,2,3,4,5]
费用= [3,4,5,1,2]
输出:3
说明:
从3号站(索引3)开始,加满4个气体。你的坦克= 0 + 4 = 4
前往车站4.您的坦克= 4 - 1 + 5 = 8
前往车站0.您的坦克= 8 - 2 + 1 = 7
前往车站1.您的坦克= 7 - 3 + 2 = 6
前往车站2.您的坦克= 6 - 4 + 3 = 5
前往车站3.费用为5.您的汽油足以返回3号站。
因此,返回3作为起始索引。
例2:
输入:
气体= [2,3,4]
费用= [3,4,3]
输出:-1
说明:
您无法从0号站或1号站开始,因为没有足够的天然气可以前往下一站。
让我们从2号站开始,填满4个单位的天然气。你的坦克= 0 + 4 = 4
前往车站0.您的坦克= 4 - 3 + 2 = 3
前往车站1.您的坦克= 3 - 3 + 3 = 3
你不能回到2号站,因为它需要4个单位的燃气,但你只有3个。
因此,无论您从哪里开始,都无法绕过电路。
思想: 若汽油和大于消费和,则一定有目标站点出现,所以遍历一次即可(排除法)
class Solution(object):
def canCompleteCircuit(self, gas, cost):
if sum(gas)<sum(cost):
return -1
profit=0
label=True
record=0
for i in range(len(gas)): #循环一次就能找到起点,由于sum(gas)<sum(cost) 证明了 一定存在这个点
if profit+gas[i]-cost[i]>0:
profit=profit+gas[i]-cost[i]
if label: #设置标志位来记录
record=i
label=False
else:
profit=0
label=True
return record
if __name__ == '__main__':
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
a=Solution().canCompleteCircuit(gas,cost)
print(a)
43、您将获得一个整数数组nums,您必须返回一个新的计数数组。counts数组具有其中count [i]是nums [i]右边的较小元素的数量的属性。
例:
输入:[5,2,6,1]
产出:[2,1,1,0]
说明:
在5的右边有2个较小的元素(2和1)。
在2的右边,只有一个较小的元素(1)。
在6的右边有1个较小的元素(1)。
在1的右边有0个较小的元素。
思路:
二分。
瓶颈依然在于插入列表中的时候需要的时间复杂度为O(n)。
思想:找到该数右边小于他的元素个数(翻译:从右向左,该数左端小于它的元素个数,即符合插入思想。且最后一个元素,一定为0),利用插入法,依次按断
class Solution(object):
# def bisect_left(self,a, x, lo=0, hi=None):
# if lo < 0:
# raise ValueError('lo must be non-negative')
# if hi is None:
# hi = len(a)
# while lo < hi:
# mid = (lo+hi)//2
# if a[mid] < x: lo = mid+1
# else: hi = mid
# return lo
def insort_left(self,nums, i):
left=0
right=len(nums)
while left<right:
mid=left+(right-left)//2
if nums[mid]<i:
left=mid+1
else:
right=mid #找左边,等号移动右指针
nums.insert(left,i)
return left
def countSmaller(self, nums): #该数右边比它小的个数等于倒置后,左边比他小的个数
x = []
result = []
for i in nums[::-1]:
#print('x',x,'i',i)
#result.append(self.bisect_left(x, i))
#print(result)
lo=self.insort_left(x,i) #思想:依次插入当前数,当前数的序号就是其与前面数的比较大小的结果
result.append(lo)
return result[::-1]
a=Solution().countSmaller([5,2,6,1])
print(a)
43、我们有一些[0,1,...,N - 1]的置换A,其中N是A的长度。
(全局)反转的数量是i <j的数量,其中0 <= i <j <N且A [i]> A [j]。
局部反演的数量是i的数量,其中0 <= i <N且A [i]> A [i + 1]。
当且仅当全局反转的数量等于本地反转的数量时才返回true。
例1:
输入:A = [1,0,2]
输出:true
说明:全局反演1次,局部反演1次。
例2:
输入:A = [1,2,0]
输出:false
说明:有2个全局反转,1个本地反转。
注意:
A将是[0,1,...,A.length - 1]的排列。
A的长度范围为[1,5000]。
此问题的时间限制已减少。
题目理解: 原数组为升序,相邻元素变化为降序就是本地翻转 ,不相邻元素变化为全局翻转
例如:【0,1,2】 本地旋转有两种: 【1,0,2】【0,2,1】剩下都是全局
44、变位词
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
class Solution(object):
def sort(self,s1):
# print(s1)
if len(s1)<=1:
return s1
mid=len(s1)//2
left=self.sort(s1[:mid])
right=self.sort(s1[mid:])
return self.merge(left,right)
def merge(self,left,right):
l,r=0,0
res=''
while l<len(left) and r<len(right):
if ord(left[l])<ord(right[r]):
res+=left[l]
l+=1
else:
res+=right[r]
r+=1
res+=left[l:]
res+=right[r:]
return res
def groupAnagrams(self, nums):
dic={}
for value in nums:
# print('value',value)
label=self.sort(value)
if label in dic:
dic[label].append(label)
else:
dic[label]=[value]
return dic.values()
a=Solution().groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
print(a)
45、两数组的重叠部分
Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2]
Example 2:
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [9,4]
思路: & 交集, | 并集,^ 并集-交集
set(nums1)&set(nums2)
45、两数组重叠部分II
Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]
Example 2:
Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
Output: [4,9]
思路:排序+双指针
class Solution(object):
def intersect(self, nums1, nums2):
result = []
nums1.sort()
nums2.sort()
l1 = 0
l2 = 0
l1_length = len(nums1)
l2_length = len(nums2)
while l1 < l1_length and l2 < l2_length:
if nums1[l1] == nums2[l2]:
result.append(nums1[l1])
l1 += 1
l2 += 1
elif nums1[l1] < nums2[l2]:
l1 += 1
else:
l2 += 1
return result
46、可被模板替换的字符串
Example 1:
Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
Output: ["mee","aqq"]
说明: abb模式有 mee , aqq 等
class Solution(object):
def findAndReplacePattern(self, words, pattern):
def translate_pattern(word):
label=[0]*len(word)
for i in range(len(word)-1):
if word[i]==word[i+1]:
label[i]=1
label[i+1]=1
return label
x = translate_pattern(pattern)
print(x)
result = []
for i in words:
if x == translate_pattern(i):
result.append(i)
return result
a=Solution().findAndReplacePattern(["abc","deq","mee","aqq","dkd","ccc"],"abb")
print(a)
返回与给定的前序和后序遍历匹配的任何二叉树。
前后遍历中的值是不同的正整数。
例1:
输入:pre = [1,2,4,5,3,6,7],post = [4,5,2,6,7,3,1]
产出:[1,2,3,4,5,6,7]
思想: 先序 后的数组一定是 [ root , 根的左树群,根的右树群]
后序后的数组一定是 [根的左树群,根的右树群,root]
树思想: 先构建根,再构建根左节点,根右节点,判断(当存在时):递归构建剩下
注意:
1 <= pre.length == post.length <= 30
pre []和post []都是1,2,...,pre.length的排列。
保证答案存在。如果存在多个答案,您可以返回任何答案。
根据二叉树的前序和后序遍历,返回一颗完整的二叉树。
不唯一,返回随便一个即可。
思路:
1.二叉树的前序是根左右。
2.二叉树的后序是左右根。
在前序中确定根,然后在后序中找左右子树。
pre = [1,2,4,5,3,6,7]
post = [4,5,2,6,7,3,1]
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def constructFromPrePost(self, nums1, nums2):
root = TreeNode(nums1[0])
def getLeftAndRight(pre, post):
# no more node.
if not pre:
return None
index = post.index(pre[0])
# post left tree
post_left = post[:index+1]
post_right = post[index+1:-1]
t = len(post_left)
pre_left = pre[:t]
pre_right = pre[t:-1]
left = pre_left[0]
right = pre_right[0] if post_right else None
return (left, right, pre_left, post_left, pre_right, post_right)
def construct(root, nums1, nums2):
x = getLeftAndRight(nums1[1:], nums2)
if root and x:
if x[0] is not None:
root.left = TreeNode(x[0])
if x[1] is not None:
root.right = TreeNode(x[1])
if root.left:
construct(root.left, x[2], x[3])
if root.right:
construct(root.right, x[4], x[5])
construct(root, nums1, nums2)
return root
一个升序数组,变为平衡二叉树
思路:可以将它看做是一颗二叉搜索树(大小排序:左树,root,右树)中序遍历后的结果
https://leetcode.com/problems/validate-binary-search-tree/description/
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
if not nums:
return None
mid=len(nums)//2
root=TreeNode(nums[mid])
left=nums[:mid]
right=nums[mid+1:]
if left:
root.left=self.sortedArrayToBST(left)
if right:
root.right=self.sortedArrayToBST(right)
return root
49、 二叉搜索树的后序遍历序列
判断给定的整数数组是不是二叉搜索树的后序遍历序列
思路:后序遍历,root在最后,且二叉搜索树其左树区间一定全部小于root,右树区间一定全部大于root,
树思想: 先判断整体满足条件,再利用指针找到第一个右子树节点,后递归判断每个子数组(分成左右两端两个子数组了,此时应设置标志位)。
def is_post_order(order):
length = len(order)
if length:
root = order[-1]
left = 0
while order[left] < root: #左树都小于root
left += 1
right = left #此时order[left] >= root, 因此直接赋予而不用right = left+1
while right < length - 1:
if order[right] < root:
return False
right += 1
label_left= True if left == 0 else is_post_order(order[:left]) #每个子树也需要符合 左 中 右 大小排序
label_right= True if left == right else is_post_order(order[left:right])
return left_ret and right_ret
return False
50、有效的二叉搜索树 (左树< 根 < 右树 )
验证是否为二叉搜索树
Input:
2
/ \
1 3
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Output: false
https://leetcode.com/problems/validate-binary-search-tree/description/
思路: 中序搜索后数组为递增数组即满足
树思想:利用临时变量来记录前一个根值。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isValidBst(self,root):
if not root:
return True
self.tmp=float('-inf') #设置一个标志数,由于要求后方为升序,因此设置为最小值
def ok(root):
if root.left:
if ok(root.left)==-1:
return -1
if root.val <= self.tmp: #此时利用 中序 查找 与上一时刻值进行比较 ,要求升序
return -1
self.tmp=root.val
if root.right:
if ok(root.right)==-1:
return -1
return
if ok(root)==-1:
return False
return True
51、跳跃游戏.
给定一个非负整数数组,您最初定位在数组的第一个索引处。
数组中的每个元素表示该位置的最大跳转长度。
确定您是否能够到达最后一个索引。
例1:
输入:[2,3,1,1,4]
输出:true
说明:从索引0跳转1步到1,然后从最后一个索引跳3步。
例2:
输入:[3,2,1,0,4]
输出:false
说明:无论如何,您总是会到达索引3。它的最大值
跳转长度为0,这使得无法到达最后一个索引。
class Solution(object):
# def is_jump(self,):
def canJump(self, nums):
tmp_max=0
record=0
for index ,value in enumerate(nums):
if tmp_max>=len(nums)-1:
return True
record=max(record,index+value)
if tmp_max==index:
tmp_max=record
return False
a=Solution().canJump([1,0,1,1,4])
print(a)
52、跳跃游戏2
输入:[2,3,1,1,4]
输出:2
说明:到达最后一个索引的最小跳转次数为2。
从索引0到1跳1步,然后从最后一个索引跳3步。
注意:
您可以假设您始终可以到达最后一个索引。
与1差不多,这个需要返回的是最少的可用步数。
class Solution(object):
def jump(self, nums):
max_reach, next_max_reach, count = 0, 0, 0
for index, value in enumerate(nums):
if max_reach >= len(nums) - 1: #当前距离能够跳出列表
return count
next_max_reach = max(next_max_reach, index + value) #记录经过的index + value 最大者
# print(next_max_reach)
if index == max_reach: #表示当前元素能够走的最远距离,如果在这个过程中,有index + value> len(nusm)-1 说明可以结束
print(index)
count, max_reach = count + 1, next_max_reach
a=Solution().jump([2,1,1,1,4])
print(a)
https://leetcode.com/contest/weekly-contest-88/problems/maximize-distance-to-closest-person/
在一排座位中,1表示坐在该座位上的人,0表示座位是空的。
至少有一个空座位,至少有一个人坐着。
亚历克斯想坐在座位上,以便他和最亲近的人之间的距离最大化。
返回距离最近的人的最大距离。
例1:
输入:[1,0,0,0,1,0,1]
输出:2
说明:
如果亚历克斯坐在第二个开放座位(座位[2]),那么最近的人有距离2。
如果Alex坐在任何其他开放式座位上,则最亲近的人的距离为1。
因此,到最近的人的最大距离是2。
例2:
输入:[1,0,0,0]
输出:3
说明:
如果Alex坐在最后一个座位上,那么最近的人就是3个座位。
这是可能的最大距离,所以答案是3。
注意:
1 <= seats.length <= 20000
席位仅包含0或1,至少一个0,至少一个1。
题意:Alex要坐在任意一个0上,问坐在哪个点上距离最近的1是最远的。
转换: 返回某0变为‘1’时,返回它距离它最近‘1’的距离
class Solution(object):
def maxDistToClosest(self, nums):
indexes = [i for i in range(len(nums)) if nums[i] == 1]
# if len(indexes)==1:
# return len(nums)-indexes[-1]-1
tmp=0
for i in range(len(indexes)-1): #中间为0
dis=indexes[i+1]-indexes[i]
tmp=max(tmp,dis)
tmp=tmp//2
print(tmp)
if indexes[-1]!=len(nums)-1: #考虑[1,0,0,0,0]的情况 右为0
tmp=max(tmp,len(nums)-1-indexes[-1])
print(tmp)
if indexes[0]!=0:
tmp=max(tmp,indexes[0]) #考虑[0,0,1*]情况 左为0
return tmp
a=Solution().maxDistToClosest([0,1,1,0,1,1,0,1])
print(a)
52、子数组的最大和
1.与当前值比(确定历史和大于0) 2、与历史比
class Solution(object):
def subsets(self, nums):
tmp=nums[0]
res=nums[0]
for i in nums[1:]:
tmp=max(i+tmp,i) #判断最大区间是加上当前值,还是重新从当前值开始计算 PS:可以避免历史和是负数
res=max(res,tmp) #历史最大值和当前最大值比较
return res
a=Solution().subsets([3,-1,2,-1])
print(a)
53、循环子数组的最大和
思路: 收尾相连=sum(nums) - sum(min A[subarray])
class Solution(object):
def maxSubarraySumCircular(self, nums):
# dp = [A[0]]
tmp=nums[0]
maxes = nums[0]
for i in nums[1:]:
tmp=max(tmp+i,i)
maxes=max(maxes,tmp)
print(maxes)
if maxes < 0:
return maxes
tmp = nums[0] #最小值
mines = nums[0]
for i in nums[1:]:
tmp=min(tmp+i,i)
mines=min(mines,tmp)
maxes = max(maxes, sum(nums) - mines) #首尾相连的情况其实就是 sum(A) - sum(min A[subarray]) 所以,最大值就是正常连续和收尾节点的最大值
return maxes
a=Solution().maxSubarraySumCircular([5,-3,5])
print(a)
54、最小下落路径和
给定一个整数A的正方形数组,我们想要通过A的下降路径的最小和。
下降路径从第一行中的任何元素开始,并从每行中选择一个元素。从上到下,每下层元素可以选择位于它之上的左中右三个元素。
例1:
输入:[[1,2,3],[4,5,6],[7,8,9]]
产量:12
说明:
可能的下降路径是:
[1,4,7],[1,4,8],[1,5,7],[1,5,8],[1,5,9]
[2,4,7],[2,4,8],[2,5,7],[2,5,8],[2,5,9],[2,6,8],[2,6,9]
[3,5,7],[3,5,8],[3,5,9],[3,6,8],[3,6,9]
最小和的下降路径是[1,4,7],所以答案是12。
注意:
1. 1 <= A.length == A [0] .length <= 100
2. -1 <= A [i] [j] <= 100
思路:从第二层开始,每个元素都选择位于它之上的三个元素中最小的一个元素。最后输出最后一层中最小的元素即可。
class Solution(object):
def minFallingPathSum(self, nums):
for x in range(1, len(nums)):
for y in range(len(nums[0])):
a = nums[x-1][y-1] if y-1 >= 0 else float('inf') #上一行,左列,不存在,则设为无限大
print(a)
b = nums[x-1][y+1] if y+1 < len(nums[0]) else float('inf') #上一行,右列
nums[x][y] += min(nums[x-1][y], a, b) #由每个最后元素得到的反演的最小路径
return min(nums[-1])
a=Solution().minFallingPathSum([[1,2,3],[4,5,6],[7,8,9]])
print(a)
Given the sorted linked list: [-10,-3,0,5,9],
One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:
0
/ \
-3 9
/ /
-10 5
56、镜像树
给定二叉树,检查它是否是自身的镜像(即,围绕其中心对称)。
例如,这个二叉树[1,2,2,3,4,3,3]是对称的:
1
/ \
2 2
/ \ / \
3 4 4 3
但是以下[1,2,2,null,3,null,3]不是:
1
/ \
2 2
\ \
3 3
注意:
如果您可以递归和迭代地解决它,那么奖励积分。
判断左子树是否与右子树互为镜像。
思路:1) 判断主树存在 3)判断两树是xiangs
https://leetcode.com/problems/symmetric-tree/submissions/
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def isSymmetric(self,root):
if not root:
return True
if self.check(root.left,root.right):
return True
return False
def check(self,left,right):
if not left and not right:
return True
if not left or not right:
return False
if left.val!=right.val:
return False
return self.check(left.left,right.right) and self.check(left.right,right.left)
55、最短路径
给一个二维数组,里面全是非负整数,找到一条左上到右下花费最小的路线。
思路:由于 起点在终点的上左,因此,最短路径一定是最后元素上左方向的最小值
class Solution(object):
def get_up_left(self, x, y): #由于 起点在终点的上左,因此,最短路径一定是最后元素上左方向的最小值
if y-1 < 0:
up = False
else:
up = (x, y-1)
if x-1 < 0:
left = False
else:
left = (x-1,y)
# up and left
return (up, left)
def minPathSum(self, nums):
for i in range(len(nums)):
for j in range(len(nums[0])):
xy = self.get_up_left(j, i)
up = nums[xy[0][1]][xy[0][0]] if xy[0] else float('inf')
left = nums[xy[1][1]][xy[1][0]] if xy[1] else float('inf')
if up == float('inf') and left == float('inf'):
continue
nums[i][j] += min(up, left)
print(nums)
return nums[-1][-1]
a=Solution().minPathSum([
[1,3,1],
[1,5,1],
[4,2,1]
])
print(a)
56、单双链表
给一个单链表,将所有的单数节点和双数节点聚合在一块,双数节点跟在单数节点后面。
Example 1:
Input: 1->2->3->4->5->NULL
Output: 1->3->5->2->4->NULL
Example 2:
Input: 2->1->3->5->6->4->7->NULL
Output: 2->3->6->7->1->5->4->NULL
class Solution(object):
def pqList(self, head):
if not head:
return head
p = head
q = head.next
q_head = q
while p.next and q.next:
p.next = p.next.next
q.next = q.next.next
p = p.next
q = q.next
p.next = q_head
return head
57、解体大数组
给定一个数组A,将其分为左右两个(连续)子阵列,以便:
左边的每个元素都小于或等于右边的每个元素。
左右都是非空的。
left具有尽可能小的尺寸。
在这样的分区之后返回左边的长度。保证存在这样的分区。
例1:
输入:[5,0,3,8,6]
输出:3
说明:left = [5,0,3],right = [8,6]
例2:
输入:[1,1,1,0,6,12]
产量:4
说明:left = [1,1,1,0],right = [6,12]
class Solution(object):
def find_point(self,nums):
lable=0
while lable<len(nums):
if max(nums[:lable+1])<=min(nums[lable+1:]):
return len(nums[:lable+1])
lable+=1
return 0
nums=[1,1,1,0,6,12]
a=Solution().find_point(nums)
print(a)
58、+1
class Solution(object):
def add_one(self,nums):
string=''
for i in nums:
string+=str(i)
string=str(int(string)+1)
dst=[]
for j in string:
dst.append(int(j))
return dst
a=[1,2,3]
print(Solution().add_one(a))
给定排序的数组nums,就地删除重复项,使每个元素只出现一次并返回新的长度。
不要为另一个数组分配额外的空间,必须通过使用O(1)额外内存修改输入数组来实现此目的。
例1:
鉴于nums = [1,1,2],
你的函数应返回length = 2,nums的前两个元素分别为1和2。
你返回的长度超出了什么并不重要。
例2:
鉴于nums = [0,0,1,1,1,2,2,3,3,4],
你的函数应该返回length = 5,将nums的前五个元素分别修改为0,1,2,3和4。
59、
Remove all elements from a linked list of integers that have value val.
Example:
Input: 1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5
class Solution(object):
def removeElements(self, head, val):
while head: #当head值为目标值时
if head.val == val:
head = head.next
else:
break
_head = head
if not _head:
return None
while head and head.next:
if head.next.val == val:
head.next = head.next.next
else:
head = head.next
return _head
60、
29)奇偶链表
60、旋转列表
Example 1:
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
Example 2:
Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL
旋转链表。 k 非负。
k 超过链表的最大长度也可。
思路:快慢指针 (考虑K值大于链表长度时)
class Solution(object):
def rotateRight(self, head, k):
if not k or not head:
return head
def getLength(node):
length = 0
while node:
node = node.next
length += 1
return length
length = getLength(head)
k = k % length
p = head
tmp=head
while k > 0:
p = p.next
k -= 1
q=p.next
dst=q
p.next=None
while q:
q=q.next
q.next=tmp
return dst
61、三角形最小路径
给定一个三角形,找到从上到下的最小路径总和。您可以移动到下面一行中相邻数字的每一步。
例如,给定以下三角形
[
[2],
[3,4],
[6,5,7]
[4,1,8,3]
]
从顶部到底部的最小路径总和是11(即,2 + 3 + 5 + 1 = 11)。
注意:
如果能够仅使用O(n)额外空间来执行此操作,则可获得奖励点,其中n是三角形中的总行数。
class Solution:
def count_min(self,nums):
length=len(nums)
for i in range(length-2,-1,-1): #从下到上一直求最小值的和
for j in range(len(nums[i])):
left=nums[i+1][j]
right=nums[i+1][j+1]
tmp=min(left,right)
nums[i][j]+=tmpa
return nums[0]
nums = [
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
k = 3
a=Solution().count_min(nums)
print(a)
63、是否是子树
B树是否是A树的子树
错误解法
class TreeNode:
def __init__(self, x=None):
self.val=x
self.left=None
self.right=None
def is_bisame(self,root1,root2):
if root1 and root2:
if root1.val==root2.val:
return self.check(root1,root2) #这种错误了,由于二叉树中不一定仅仅出现一个大小相等的点
else:
return self.is_bisame(root1.left,root2) or self.is_bisame(root1.right,root2)
def check(self,root1,root2):
if not root1:
return False
if not root2:
return True
if root1.val!=root2.val:
return False
return self.check(root1.left,root2.left) and self.check(root1.righr,root2.right)
if __name__ == '__main__':
node1=TreeNode(8)
node2 = TreeNode(8)
node3 = TreeNode(7)
node4 = TreeNode(9)
node5 = TreeNode(2)
node6 = TreeNode(4)
node7 = TreeNode(7)
node1.left,node1.right=node2,node3
node2.left,node2.right=node4,node5
node5.left,node5.right=node6,node7
#树二
node8 = TreeNode(8)
node9 = TreeNode(9)
node10 = TreeNode(2)
node8.left, node8.right = node9, node10
print(TreeNode().is_bisame(node1,node8))
正确解法:
class TreeNode:
def __init__(self, x=None):
self.val=x
self.left=None
self.right=None
class Solution:
def is_bisame(self,root1,root2):
label=False
if root1 and root2:
if root1.val==root2.val:
label= self.check(root1,root2) #设置标志位
if not label:
label=self.is_bisame(root1.left,root2)
if not label:
label=self.is_bisame(root1.right,root2)
return label
def check(self,root1,root2):
if not root2: #研究了半天,我们必须先判定root2 不能先判定root1 由于,root1和root2同时为Null 条件也成立
return True
if not root1:
return False
if root1.val!=root2.val:
return False
return self.check(root1.left,root2.left) and self.check(root1.right,root2.right)
if __name__ == '__main__':
# 树1
node1 = TreeNode(8)
node2 = TreeNode(8)
node3 = TreeNode(7)
node4 = TreeNode(9)
node5 = TreeNode(2)
node6 = TreeNode(4)
node7 = TreeNode(7)
node1.left, node1.right = node2, node3
node2.left, node2.right = node4, node5
node5.left, node5.right = node6, node7
# 树2
node8 = TreeNode(8)
node9 = TreeNode(9)
node10 = TreeNode(2)
node8.left, node8.right = node9, node10
print(Solution().is_bisame(node1, node8))
69、镜像二叉树
给二叉树A ,输出其镜子中的对应二叉树
思路: 左子树与右子树易位,利用先序输出
class BinartTreeNode:
def __init__(self,val=None,left=None,right=None):
self.val = val
self.left = left
self.right = right
def MirrorRecurisively(root):
if root:
root.left,root.right = root.right,root.left
MirrorRecurisively(root.left)
MirrorRecurisively(root.right)
def preOrder(root):
if root:
print(root.val,end=' ')
preOrder(root.left)
preOrder(root.right)
if __name__ == '__main__':
node1 = BinartTreeNode(8)
node2 = BinartTreeNode(6)
node3 = BinartTreeNode(10)
node4 = BinartTreeNode(5)
node5 = BinartTreeNode(7)
node6 = BinartTreeNode(9)
node7 = BinartTreeNode(11)
node1.left,node1.right = node2,node3
node2.left,node2.right = node4,node5
node3.left,node3.right = node6,node7
preOrder(node1)
print('\n')
MirrorRecurisively(node1)
preOrder(node1)
70、螺旋矩阵II
Input: 3
Output:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
class Solution:
def maybe(self,x,y):
return [(x,y+1),
(x+1,y),
(x,y-1),
(x-1,y)]
def travl(self,n):
label=[[0 for i in range(n)] for j in range(n)]
target=[i for i in range(1,n*n+1)] #将[1, 2, 3, 4, 5, 6, 7, 8, 9] 排序成为#[[1, 2, 3], [8, 9, 4], [7, 6, 5]]
print(target)
def go_right(x,y):
while True:
if not target:
return label
tmp=self.maybe(x,y)
if (x>-1 and y>-1) and (x<n and y<n):
if label[x][y]==0:
label[x][y]=target.pop(0)
x,y=tmp[0][0],tmp[0][1] #x,y向右移动
else:
return go_down(x+1,y-1) #即表示该时刻(x,y+1)已经去过,重新选点(x+1,y-1)表示想下
else:
go_down(x+1,y-1) #**************************重点(躺了N次坑,由于该点表示越界或已经遍历过时情况(我们应该将此时越界的点正确调整到下一时刻应该判断的点位)
def go_down(x,y):
while True:
if not target:
return label
tmp=self.maybe(x,y)
if (x>-1 and y>-1) and (x<n and y<n):
if label[x][y]==0:
label[x][y]=target.pop(0)
x,y=tmp[1][0],tmp[1][1]
else:
return go_left(x-1,y-1)
else:
go_left(x-1,y-1)
def go_left(x,y):
while True:
if not target:
return label
tmp=self.maybe(x,y)
if (x>-1 and y>-1) and (x<n and y<n):
if label[x][y]==0:
label[x][y]=target.pop(0)
x,y=tmp[2][0],tmp[2][1]
else:
return go_up(x-1,y+1)
else:
go_up(x-1,y+1)
def go_up(x,y):
while True:
if not target:
return label
tmp=self.maybe(x,y)
if (x>-1 and y>-1) and (x<n and y<n):
if label[x][y]==0:
label[x][y]=target.pop(0)
x,y=tmp[3][0],tmp[3][1]
else:
return go_right(x+1,y+1)
else:
go_up(x+1,y+1)
return go_right(0,0)
a=Solution().travl(3)
print(a)
71、二叉搜索树与双向链表
class Solution:
def Convert(self, root):
if not root:
return
self.tmp = []
self.tree(root)
for i in range(len(self.tmp)-1):
self.tmp[i].right = self.tmp[i+1]
self.tmp[i+1].left = self.tmp[i]
return self.tmp[0]
def tree(self, root):
if not root:
return
self.tree(root.left)
self.tmp.append(root)
self.tree(root.right)
63、和为0的最长子数组
思路:将问题统一转化为求SUM数组两个相同数字最远距离
class Solution: #用空间换时间,联合使用
def traval(self,nums):
res=[0]*len(nums)
res[0]=nums[0]
for i in range(1,len(nums)):
res[i]=res[i-1]+nums[i]
max_tmp=0
left_label=0
right_label=0
for left in range(len(res)):
for right in range(len(res)-1,left,-1):
if res[left]==res[right]:
if right-left>max_tmp:
left_label=left
right_label=right
max_tmp=right-left
break
if res[right]==0:
if right+1>max_tmp:
left_label=0
right_label=right
max_tmp=right+1
return nums[left_label+1:right_label+1]
a=Solution().traval([7,-7,8,6,5,-5,-5,0,-6,11])
print(a)
64、从上到下打印二叉树.py
class TreeNode:
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
class MyQueue:
def __init__(self):
self.Queue = []
def enqueue(self, data):
self.Queue.append(data)
def dequeue(self):
return self.Queue.pop(0)
def Print(self):
print(self.Queue)
def Size(self):
return len(self.Queue)
# 不分行从上到下打印二叉树
def PrintFromTopToBottom(Node):
if not isinstance(Node, TreeNode):
return
Queue = MyQueue()
Queue.enqueue(Node)
while Queue.Size():
temp = Queue.dequeue()
print(temp.data, end=' ')
if temp.left:
Queue.enqueue(temp.left)
if temp.right:
Queue.enqueue(temp.right)
# 分行从上到下打印二叉树
def PrintFromTopToBottom_2(Node):
if not isinstance(Node, TreeNode):
return
Queue = MyQueue()
toBePrinted, nextLevel = 1, 0 # toBePrinted表示本层未打印节点的数量,nextLevel表示下层要打印节点的数量
Queue.enqueue(Node)
while Queue.Size():
temp = Queue.dequeue()
print(temp.data,end=' ')
toBePrinted -= 1
if temp.left:
nextLevel += 1
Queue.enqueue(temp.left)
if temp.right:
nextLevel += 1
Queue.enqueue(temp.right)
if toBePrinted == 0:
print()
toBePrinted = nextLevel
nextLevel = 0
# 之字形打印二叉树
# 需要利用两个栈来管理奇数层和偶数层
def PrintFromTopToBottom_3(Node):
if not isinstance(Node, TreeNode):
return
stack1,stack2 = [Node],[]# 奇数栈从左往右打印,偶数栈从右往左打印
stack = [stack1,stack2]
current,next = 0,1
while stack1 or stack2:
temp = stack[current].pop()
print(temp.data,end=' ')
if current == 0:
#在奇数层,下一层应该从右到左压入
if temp.left:
stack[next].append(temp.left)
if temp.right:
stack[next].append(temp.right)
else:
if temp.right:
stack[next].append(temp.right)
if temp.left:
stack[next].append(temp.left)
if not stack[current]:
# 说明该层打印完了
print()
current = 1 -current
next = 1- next
node1 = TreeNode(8)
node2 = TreeNode(6)
node3 = TreeNode(10)
node4 = TreeNode(5)
node5 = TreeNode(7)
node6 = TreeNode(9)
node7 = TreeNode(11)
node1.left, node1.right = node2, node3
node2.left, node2.right = node4, node5
node3.left, node3.right = node6, node7
#PrintFromTopToBottom(node1)
PrintFromTopToBottom_2(node1)
#PrintFromTopToBottom_3(node1)
77、序列化二叉树.
class TreeNode:
def __init__(self,data=None,left=None,right=None):
self.data = data
self.left = left
self.right = right
def Serialize(root,serializelis):
if not root:
serializelis.append('$')
return
serializelis.append(str(root.data))
Serialize(root.left,serializelis)
Serialize(root.right,serializelis)
def Deserialize(serializelis):
tree,count = deserlialize(serializelis,0)
return tree
def deserlialize(serializelis,count):
if count >= len(serializelis) or serializelis[count]=='$':
return None,count+1
node = TreeNode(int(serializelis[count]))
count += 1
node.left,count = deserlialize(serializelis,count)
node.right,count = deserlialize(serializelis,count)
return node,count
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)
node1.left,node1.right = node2,node3
node2.left = node4
node3.left,node3.right = node5,node6
serializelis =[]
Serialize(node1,serializelis)
print(serializelis)
tree = Deserialize(serializelis)
print(tree.left.data)
78、二叉树中和为某一值的路径
思路: 利用递归追根节点,后用path 记录路径 1)满足条件打印,后弹出 2)不满足条件直接弹出
path 列表利用先序sort元素,后序弹出元素
class TreeNode:
def __init__(self,data=None,left=None,right=None):
self.data = data
self.left = left
self.right = right
def FindPath(root,n):
path = []
tmp = 0
Find_Path(root,n,path,tmp)
def Find_Path(root,n,path,tmp):
tmp += root.data
path.append(root)
# print('tmp',tmp) #10->15->19->22->22
if tmp == n and not root.left and not root.right: #找到目标且该路径到底了
for i in path: #
print(i.data,end=' ')
print()
# 如果不是叶节点,则遍历它的子节点
if root.left:
Find_Path(root.left,n,path,tmp)
if root.right:
Find_Path(root.right,n,path,tmp)
# 在返回父节点之前,在路径上删除当前节点
a=path.pop(-1)
# print('111',a.data)
node1 = TreeNode(10)
node2 = TreeNode(5)
node3 = TreeNode(12)
node4 = TreeNode(4)
node5 = TreeNode(7)
node1.left,node1.right = node2,node3
node2.left,node2.right = node4,node5
FindPath(node1,22)
79、二叉树的最近公共祖先
class Solution:
def search(self,root,node1,node2):
if not root:
return #找不到值,返回空
if root==node1 or root==node2:
return root #找到值,返回值
left=self.search(root.left,node1,node2) #当左子树找到时,返回指针
right=self.search(root.right,node1,node2) #当右子树找到时,返回指针
if left and right:
return root #当前节点,左子树和右子树有能找值,返回其公共节点
if left:
return right #说明当前节点,左子树能找到值,右子树找不到,说明后序查找中,右子树找到值更接近主树,返回右节点
if right:
return left
return None
当前置条件为二叉搜索树时:
class Solution:
# 当树为二叉搜索树的情况
def GetLowestNodeParent(root,node1,node2):
if not node1 or not node2:
return
p = root
# 保证p1指向值小的节点,而p2指向值大的节点
p1, p2 = node1, node2
if p1.data > p2.data:
p1, p2 = node2, node1
while p.data > p2.data or p.data < p1.data:
if p.data > p2.data:
p = p.left
else:
p = p.right
return p
80、二叉树的最大路径和.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def maxPathSum(self, root):
self.maxes = -float('inf')
def helper(root):
if not root.left and not root.right:
self.maxes = root.val if root.val > self.maxes else self.maxes
return root.val
valueLeft, valueRight = -float('inf'), -float('inf')
if root.left:
valueLeft = helper(root.left)
if root.right:
valueRight = helper(root.right)
# judge left to right is max or not.
self.maxes = max([root.val + valueLeft, root.val + valueRight, root.val + valueLeft + valueRight, root.val, self.maxes])
print('root',root.val)
print('valueLeft',valueLeft,'valueRight',valueRight)
# return to parent
return max(root.val + max(valueLeft, valueRight), root.val)
helper(root)
return self.maxes
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(3)
node4 = TreeNode(4)
node5 = TreeNode(5)
node6 = TreeNode(6)
node7 = TreeNode(7)
node1.left,node1.right = node2,node3
node2.left,node2.right = node4,node5
node3.right = node6
node5.left = node7
a = Solution()
# print(a.TreeDepth(node1))
print(a.maxPathSum(node1))
79、滑窗法
class Solution(object):
def minSubArrayLen(self, nums,s):
l=0
r=-1
sum=0
res=len(nums)+1
while l<=len(nums)-1:
if sum<s and r<len(nums)-1:
r+=1
sum+=nums[r]
else:
print('nums',nums[l])
sum-=nums[l]
print('l',l)
l+=1
if sum>=s:
res=min(res,r-l+1)
if res==len(nums)+1:
return 0
return res
nums=[6,5,3,1,9,12,4,2]
print(Solution().minSubArrayLen(nums,20))
80、