文章目录
WC133 子数组的最大累加和问题
思路:从头到尾逐渐累加,每加一次,更新一次最大累加和,若和小于零,重新开始累加
class Solution:
def maxsumofSubarray(self , arr ):
# write code here
sub_max = 0
sub = 0
for i in arr:
if sub <0:
sub = i
else:
sub += i
sub_max = max(sub,sub_max)
return sub_max
WC136 最长无重复子数组
思路1,使用一个临时数组作为子数组,遍历一遍
class Solution:
def maxLength(self , arr ):
if len(arr) in [0,1]:
return len(arr)
max_sub = 0 #最大无重复长度
tem_arr = [] #子数组
for i in arr:
if i not in tem_arr: #当前值不在子数组中
tem_arr.append(i)
max_sub = max(max_sub,len(tem_arr))
else:
start = tem_arr.index(i) #当前值在子数组中
tem_arr = tem_arr[start+1:] #从重复元素的下一个开始重新计算
tem_arr.append(i)
return max_sub
双指针
class Solution:
def maxLength(self , arr ):
if len(arr) in [0,1]:
return len(arr)
longest_length,i,j = 0, 0, 0
arr_length = len(arr)
while j < arr_length:
try:
index = arr[i:j].index(arr[j]) #若切片内存在下一个值,更新左指针
longest_length = max(longest_length, j-i)
i = index+i+1
except ValueError:#若不存在 t
pass
j += 1 #右指针每次向前一步
return max(longest_length, j-i)
NC119 最小的K个数
返回数组中最小的k个数,不需要按从小到大的顺序
思路:利用quick_sort的思想,当节点左边刚好有k-1个元素小,此节点加上左边的k-1个元素就是结果
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if len(tinput) == 0 or k == 0:
return []
if len(tinput) == k:
return tinput
left = 0
right = len(tinput)-1
l = tinput
left = self.quick_sort(l, left, right)
while left != k-1:
if left < k-1: #当左边数量不足,向右寻找
left = self.quick_sort(l, left+1, right)
if left > k-1:#当左边数量过多,向左寻找
left = self.quick_sort(l, 0,left -1 )
return l[:k]
# 偷懒解法
# tinput.sort()
# return tinput[:k]
def quick_sort(self,l,left,right):
low = left
point = l[left]
high = right
while low < high:
while low<high and point <= l[high]:
high -= 1
while low<high and point >= l[low]:
low += 1
self.swap(l, low,high)
self.swap(l, left, low)
return low
def swap(self,l,i,j):
temp = l[i]
l[i]= l[j]
l[j] = temp
NC68 跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法
对这种问题需要首先写出递推公式:f(0) = 0 ,f(1) = 1,f(2)= 2 ,f(3) = f(1)+f(2),....f(n) = f(n-1)+f(n-2)
,然后利用循环即可
class Solution:
def jumpFloor(self, number):
# write code here
if number in [0,1,2]:
return number
f_n_1,f_n_2,f_n = 1,2,0 #f(1),f(2)
for i in range(2,number+1):
f_n = f_n_1 + f_n_2 #求fn
f_n_1 = f_n_2 # 向前一步
f_n_2 = f_n
return f_n
NC61 两数之和
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2
class Solution:
def twoSum(self , numbers , target ):
# write code here
length = len(numbers)
for i in range(length -1):
x1 = numbers[i]
if x1 > target:
continue
else:
try:
j = numbers[i+1:].index(target-x1)
return i+1,i+j+2
except ValueError:
pass
WC135 两个链表生成相加链表
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
使用列竖式加法的方法,从尾部到头部开始相加,注意进位
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
#
# @param head1 ListNode类
# @param head2 ListNode类
# @return ListNode类
#
class Solution:
def addInList(self , head1 , head2 ):
# write code here
s1 = self.read(head1)
s2 = self.read(head2)
carry,s = 0,0 #进位,每一步加和的值
tem = []#存储新链表
while len(s1)>0 or len(s2)>0:#当两个链表都为空时,退出链表
if len(s1)>0:
x1 = s1.pop()
else:
x1 = 0
if len(s2)>0:
x2 = s2.pop()
else:
x2 = 0
s = x1+x2+carry
if s >=10:
carry = 1 #更新进位
tem.append(s-10)
else:
carry = 0 #更新进位
tem.append(s)
if carry ==1: #添加头部进位
tem.append(1)
tem.reverse() #反转列表
head = ListNode(tem[0])
r_head = head #保存新链表的头
for i in range(1,len(tem)):
head.next = ListNode(tem[i])
head = head.next
return r_head
def read(self,head):
'''
读取链表
'''
if head is None:
return None
tem = []
while head:
tem.append(head.val)
head = head.next
return tem
WC139 在二叉树中找到两个节点的最近公共父节点
给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
注:本题保证二叉树中每个节点的val值均不相同。
思路1:找到两个节点的路径,路径第一个不相同的值,就是公共父节点
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
#
# @param root TreeNode类
# @param o1 int整型
# @param o2 int整型
# @return int整型
#
class Solution:
def lowestCommonAncestor(self , root , o1 , o2 ):
# write code here
l1 = []
l2 = []
l3 = [False] #引用变量来标识是否找到o
self.dfs(l1, root, o1,l3)
l3[0] = False
self.dfs(l2, root, o2,l3)
leng = min(len(l1),len(l2))
for i in range(1,leng):
if(l1[i] != l2[i]):
return l1[i-1]
return l1[leng-1]
def dfs(self,res,root,o,l):
'''返回找到o节点的路径'''
if l[0] or root is None:#已经找到o或达到空节点:
return
res.append(root.val) #添加当前节点的值
if root.val == o: #若遇到o,则返回
l[0] = True
return
self.dfs(res,root.left,o,l) #否则,向左查找
self.dfs(res,root.right,o,l) #否则,向右查找
if l[0]: #避免o被弹出
return
res.pop()#不在这条路径,弹出该节点的值
思路2:递归方法
class Solution:
def lowestCommonAncestor(self , root , o1 , o2 ):
# write code here
return self.dfs(root, o1, o2).val
def dfs(self,root,o1,o2):
'''返回找到o节点的路径'''
if root is None: #若遇到空节点,返回None
return None
if root.val in [o1,o2]: #若遇到两个节点中的一个,返回此节点
return root
t1 = self.dfs(root.left, o1, o2) # 否则,分别继续向左右寻找
t2 = self.dfs(root.right, o1, o2)
if t1 is None and t2 is None: # 左右都为空,返回None
return None
elif t1 is None and t2 is not None: #左空,右不空,返回右节点
return t2
elif t1 is not None and t2 is None:
return t1
else:#左右都不空,返回父节点
return root
WC132 最长递增子序列
最长递增子序列
给定数组arr,设长度为n,输出arr的最长递增子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)
输入:[1,2,8,6,4]
返回值:[1,2,4]
说明:其最长递增子序列有3个,(1,2,8)、(1,2,6)、(1,2,4)其中第三个 按数值进行比较的字典序 最小,故答案为(1,2,4) ,就是返回结果中最靠后的那一个
#
# retrun the longest increasing subsequence
# @param arr int整型一维数组 the array
# @return int整型一维数组
#
class Solution:
def LIS(self , arr ):
tem = [] #存放最长递增序列
tem_len = [] #存放以arr[i]为结尾的最长递增序列的长度
length = len(arr) #arr长度
if length in [0,1]:
return arr
#添加第一个元素
tem = [arr[0]]
tem_len = [1]
for num in arr[1:]:
if num > tem[-1]:#如果大于上一个元素
tem.append(num)
tem_len.append(len(tem))
else: #否则寻找tem中第一个大于num的数,并替换它
#二分法寻找
left,right = 0,len(tem)-1
while left < right:
mid = (left + right) // 2
if tem[mid] < num:
left = mid +1
elif tem[mid] == num:
left = mid
break
else:
if tem[mid-1] <num:
left = mid
break
else:
right = mid -1
tem[left] = num
tem_len.append(left+1)
max_len = len(tem) #最大递增子序列的长度
#从后向前迭代tem_len,若等于max_len,返回arr中对应的元素
for i in range(length -1,-1,-1):
if tem_len[i] == max_len:
tem[max_len-1] = arr[i]
max_len -= 1
return tem
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LLfeFsjO-1631422147913)(C:\Users\lipan\OneDrive - mail.hfut.edu.cn\note\算法练习.assets\image-20210910140521390.png)]
刚开始写错了,写成了返回最大递增连续序列
#
# retrun the longest increasing subsequence
# @param arr int整型一维数组 the array
# @return int整型一维数组
#
class Solution:
def LIS(self , arr ):
# write code here
length = len(arr)
tem = [] #存放所有递增子序列
result = [] # 过程中产生的递增子序列
for i in range(length):
if i == length -1:
if len(result) == 0:
tem.append([arr[-1]])
elif result[-1] >= arr[-1]:
tem.append(result)
tem.append([arr[-1]])
else:
result.append(arr[-1])
tem.append(result)
break
result.append(arr[i])
if arr[i]<arr[i+1]:
continue
elif arr[i] >= arr[i+1]:
tem.append(result.copy())
result = []
tem_len = [len(x) for x in tem]
max_len = max(tem_len)
re = [ x for x in tem if len(x) == max_len]
result_final = []
if len(re) == 1:
return re[0]
else:
for i in range(len(re)-1):
if re[i]>=re[i+1]:
result_final = re[i]
return result_final
NC33 合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
遍历两个链表,将新链表的当前节点指向比较小的节点,并分别向前移动一个节点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
new_head = ListNode(-1) #新链表的头
cur = new_head #新链表的当前节点
while pHead1 or pHead2:
if pHead1 is not None and pHead2 is not None:#两者都不为空
x1 = pHead1.val
x2 = pHead2.val
if x1<=x2:
cur.next = pHead1 #指向比较小的节点
cur = cur.next #cur向前一步
pHead1 = pHead1.next #链表1向前一步
elif x1>x2:
cur.next = pHead2
cur = cur.next
pHead2 = pHead2.next
elif pHead1 is None and pHead2 is not None:#其中一个为空
cur.next = pHead2
break
elif pHead1 is not None and pHead2 is None:
cur.next = pHead1
break
else:
break
return new_head.next
NC50 链表中的节点每k个一组翻转
要求:空间复杂度为1
思路
- 求链表长度
- 将链表按照长度k进行切片
- 将每个切片反转
- 连接反转后的切片
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
#
# @param head ListNode类
# @param k int整型
# @return ListNode类
#
class Solution:
def reverseKGroup(self , head , k ):
# write code here
if head is None:
return head
if head.next is None:
return head
l = self.length(head) #链表的长度
if k >l :
return head
nums = l // k
cur = head #复制一个链表头
new_head = ListNode(-1) #第一个切片的头,也就是新链表的头
start = ListNode(-1) #每个切片的头
end = ListNode(-1) #每个切片的尾
start = head
for j in range(k-1):
cur = cur.next
end = cur
cur = cur.next
end.next = None #截断链表
start,end = self.reverse(start) #反转切片中链表
new_head = start
slice_end = end
for i in range(nums -1 ):
#截取一个长度为k的切片
start = cur
for j in range(k-1):
cur = cur.next
end = cur
# 进入该切片的下一个节点
cur = cur.next
end.next = None #截断链表
start,end = self.reverse(start) #反转切片中链表
slice_end.next = start
slice_end = end
slice_end.next = cur
return new_head
def reverse(self,pHead):
'''反转链表'''
pre = ListNode(None) # 存储新链表的头
cur = pHead
nex = ListNode(None) # 与cur一起遍历整个链表
end = ListNode(None)
while cur is not None:
nex = cur.next
if cur == pHead:#判断是否是头
cur.next = None # 生成新链表的尾
end = cur
else:
cur.next = pre # 反转节点的方向,指向新链表
pre = cur #将新链表的头指向新节点
cur = nex #将cur指向下个节点
# 当遍历到最后一个节点时,nex会变成None,从而cur会变成None,退出循环
return pre,end
def length(self,head):
'''
求链表长度
'''
l = 1
while head.next:
head = head.next
l+=1
return l
WC141 输出二叉树的右视图
请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图
根据二叉树的中序遍历和前序遍历,还原二叉树 - xinchrome - 博客园 (cnblogs.com)
方法:前序遍历每次读取都是当前节点,中序遍历先读左,因此中序遍历的root两边分别是左子树和右子树
下面代码中,count是统计每一层,dic记录每一层的最右边的节点值,下图是执行上面输入,打印出的dic添加情况
![image-20210912124616922](算法练习.assets/image-20210912124616922.png)
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
# 求二叉树的右视图
# @param xianxu int整型一维数组 先序遍历
# @param zhongxu int整型一维数组 中序遍历
# @return int整型一维数组
#
class Solution:
def solve(self , xianxu , zhongxu ):
# write code here
count = 0
dic = {}
self.recurve(xianxu,zhongxu,count,dic)
i = 1
ans = []
while i in dic.keys():
ans.append(dic[i])
i+=1
return ans
def recurve(self,xianxu,zhongxu,count,dic):
'''
重构二叉树
'''
count += 1
if not zhongxu: #某一个为空时,函数返回
return
if not xianxu:
return
mid = zhongxu.index(xianxu[0]) #找到中序遍历的root
root = treenode(xianxu[0])
del xianxu[0]#弹出root
if mid == 0: #如果mid=0,说明左边没有节点了
root.left = None
else: #否则,继续向左
root.left = self.recurve(xianxu,zhongxu[0:mid],count,dic)
if mid == len(zhongxu)-1: #如果mid是最后一个元素,说明右边没节点了,继续向右
root.right = None
else:
root.right = self.recurve(xianxu,zhongxu[mid+1:len(zhongxu)],count,dic)
dic[count] = root.val
return root
class treenode:
def __init__(self,val):
self.val = val
self.left = None
self.right = None