python数据结构与算法-第2弹

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

思路

  1. 求链表长度
  2. 将链表按照长度k进行切片
  3. 将每个切片反转
  4. 连接反转后的切片
# 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两边分别是左子树和右子树

image-20210912124427651

下面代码中,count是统计每一层,dic记录每一层的最右边的节点值,下图是执行上面输入,打印出的dic添加情况

image-20210912124616922
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
# 求二叉树的右视图
# @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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值