剑指offer_Python解题(二)

15、反转链表

输入一个链表,反转链表后,输出新链表的表头

15.1 思路

  • 思路

考虑头为空时,其他的依次赋值

15.2 解题

def Reverslist(phead):
    out_l = None
    while phead:
        # next针指向上一个
        out_l, out_l.next,  = phead, out_l
        phead = phead.next
    return out_l

16、合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

16.1 思路

  • 思路

逐一比较并合并

16.2 解题

创建个 chainlist
class ChainNode():
    def __init__(self, val, pnext = None):
        self.val = val
        self._next = pnext

class createChain(ChainNode):
    def __init__(self, val_list, head = None):
        self.len = len(val_list)
        self.chain = ChainNode(head if head != None else None)
        self.create_chain(val_list)

    def create_chain(self, val_list: list) -> ChainNode:
        node_loop = self.chain
        for i in val_list:
            node_loop._next = ChainNode(i)
            node_loop = node_loop._next
    
    def _empt(self):
        """
        是否只有一个head
        """
        return  self.len == 0

    def append(self, val):
        """ 
        在链表最后添加一个节点 或 链表
        """
        if isinstance(val, ChainNode):
            add_ = ChainNode(val)
            val_chain = val
            while val_chain:
                val_chain = val_chain._next
                self.len += 1
        else:
            add_ = val
            self.len += 1

        node_loop = self.chain
        while node_loop._next:
            node_loop = node_loop._next
        node_loop._next = add_


c1_lst = [1, 2, 3, 5, 6, 8, 10, 20]
c2_lst = [4, 7, 9, 10, 11]
chain_c1 = createChain(c1_lst, head=None)
chain_c2 = createChain(c2_lst, head=None)
  • 解题
import copy
def Merge(chain_1, chain_2):
    if chain_1 == None:
        return chain_2
    if chain_2 == None:
        return chain_1
    # 保护原数据
    chain1 = copy.deepcopy(chain_1) 
    chain2 = copy.deepcopy(chain_2)
    cur_chain = None
    val1 = 0 if chain1.val == None else chain1.val
    val2 = 0 if chain2.val == None else chain2.val
    if val1 < val2:
        cur_chain = chain1
        cur_chain._next = Merge(chain1._next, chain2)
    else:
        cur_chain = chain2
        cur_chain._next = Merge(chain1, chain2._next)
    return cur_chain

## 输入的一个链表带头一个不带(这个是由于自己写的chain结构的原因)
cur_chain = Merge(chain_c1.chain._next, chain_c2.chain)

p_ = cur_chain
while p_:
    print(f'当前节点值:{p_.val}')
    p_ = p_._next
"""
>>> while p_:
...     print(f'当前节点值:{p_.val}')
...     p_ = p_._next
...
当前节点值:None
当前节点值:1
当前节点值:2
当前节点值:3
当前节点值:4
当前节点值:5
当前节点值:6
当前节点值:7
当前节点值:8
当前节点值:9
当前节点值:10
当前节点值:10
当前节点值:11
"""

17、树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(空树不是任意一个树的子结构)

17.1 思路

  • 思路

1- 递归遍历 tree_Atree_B
2- 停止条件1:B先穷尽返回True ,A先穷尽返回False
3- 遍历判断条件:A与B树的值是否相同
4- 由于是B可能是子树, 所以要先遍历A到子树与B的子树节点相同的时候,再去判断是否相同

17.2 解题


class subTree_judge():
    def isSubTree(self, tree_A, tree_B):
        """
        查看节点相同的两个树
        B 是不是 A的子树
        """
        if tree_B == None:
            return True
        if tree_A == None:
            return False
        if tree_A.val != tree_B.val:
            return False
        return self.isSubTree(tree_A.left, tree_B.left) & self.isSubTree(tree_A.right, tree_B.right)

    def HasSubtree(self, tree_A, tree_B):
        if not tree_A or not tree_B:
            return False
        result = False
        if tree_A.val == tree_B.val:
            result = self.isSubTree(tree_A, tree_B)
        if not result: # 直到寻找到 节点相同的时候再去做判断
            result = self.HasSubtree(tree_A.left, tree_B)
        if not result:
            result = self.HasSubtree(tree_A.right, tree_B)
        return result


# 测试
from scc_function.Struct import BTree # 一个简单的类 仅有__init__
tree_B = BTree(val=2, left=BTree(6), right=BTree(8))
tree_A = BTree(val=2, left=BTree(10, tree_B),
               right=BTree(19, BTree(3), BTree(5)))

subTree_judge().HasSubtree(tree_A, tree_B)

"""
>>> subTree_judge().HasSubtree(tree_A, tree_B)
True
"""

18、二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

二叉树的镜像定义:
源二叉树 :
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	
镜像二叉树  :
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5

18.1 思路

  • 思路

1- 递归遍历 左右互换

18.2 解题

import copy
def invertTree(tree_in):
    tree = copy.deepcopy(tree_in)
    if not tree:
        return None
    tree.left,tree.right = invertTree(tree.right), invertTree(tree.left)
    return tree

tree_B = BTree(val=2, left=BTree(6), right=BTree(8))
tree_B_mirr = invertTree(tree_B)

"""
>>>
>>> print(f'原tree_B.left: {tree_B.left.val}, 镜像tree_B.left:{tree_B_mirr.left.val}\
...       \n原tree_B.right: {tree_B.right.val}, 镜像tree_B.left: {tree_B_mirr.right.val}')
原tree_B.left: 6, 镜像tree_B.left:8
原tree_B.right: 8, 镜像tree_B.left: 6
"""

19、顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

19.1 思路

  • 思路

0- 递归遍历
1- 需要第一行 和 最后行倒序
2- 需要中间行行首和行尾
3- 停止条件 arr == []
4- 特殊情况当arr只有一行或者两行的时候

19.2 解题

import copy
class Solution():
    def printMatrix(self, arr_in):
        arr = copy.deepcopy(arr_in)
        out_lst = []
        while arr != []:
            out_circle, arr = self.get_circle(arr)
            out_lst.extend(out_circle)
        return out_lst
        
    def get_circle(self, arr):
        """
        一圈遍历
        返回:
            第一外圈顺时针遍历结果
            接下来可能要遍历的数组
        """
        if len(arr) == 1:
            return arr[0], []
        if len(arr) == 2:
            return arr[0] + arr[1][::-1], []
        out_lst = arr[0]
        tmp, arr_next = [], []
        for line_i in arr[1:-1]:
            out_lst.append(line_i[-1])
            tmp.append(line_i[0])
            arr_next.append(line_i[1:-1])
        return out_lst + arr[-1][::-1] + tmp[::-1], arr_next


arr = [[1, 2, 3, 10], [4, 5, 6, 29], [7, 8, 9, 38], [10, 11, 12, 40]]
slv = Solution()
slv.printMatrix(arr)
"""
>>> slv.printMatrix(arr)
[1, 2, 3, 10, 29, 38, 40, 12, 11, 10, 7, 4, 5, 6, 9, 8]
"""

20、包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

20.1 思路

  • 思路

0- 建立一个辅助栈,每增加一个数,保存目前所有数的最小值在辅助栈的栈最后。

20.2 解题

class Stack_list:
    def __init__(self):
        self.stack = []
        self.minStack = []
        
    def push(self, val):
        """
        将栈中当前最小值压如辅助栈中
        """
        self.stack.append(val)
        if (self.minStack == []) or (val < self.min()):
            self.minStack.append(val)
        else:
            temp = self.min()
            self.minStack.append(temp)
        
    def pop(self):
        try:
            self.minStack.pop()
            self.stack.pop()
        except:
            return None
        
    def top(self):
        try:
            return self.stack[-1]
        except:
            return None
        
    def min(self):
        try:
            return self.minStack[-1]
        except:
            return None



stk_lst = Stack_list()
stk_lst.push(1)
stk_lst.push(2)
stk_lst.push(3)
stk_lst.push(4)
stk_lst.push(5)
stk_lst.push(-1)
stk_lst.push(-1)
stk_lst.min()
stk_lst.stack, stk_lst.minStack
"""
>>> stk_lst.min()
-1
>>> stk_lst.stack, stk_lst.minStack
([1, 2, 3, 4, 5, -1, -1], [1, 1, 1, 1, 1, -1, -1])
>>>
"""

21、栈的压入、弹出

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

21.1 思路

  • 思路

0- 依次遍历
1- 当值相等的时候,弹出

21.2 解题

import copy
def IsPopOrder(pushlst, poplst_in):
    poplst = copy.deepcopy(poplst_in)
    for p in pushlst:
        n = 0
        for out in poplst:
            if p == out:
                poplst.pop(n)
            n += 1
    return poplst == []


a = [1, 2, 3, 4, 5]
b = [4, 5, 3, 2, 1]
IsPopOrder(a, b)
"""
>>> IsPopOrder(a, b)
True
"""

21.3 优化解题

  • 优化思路

0- 仍旧考虑先压入的会先弹出, 弹出后会在poplst的底部
1- 所以比较 pushlst[0] 和 poplst[0]
2- 但是会存在压入最后才弹出的情况,所以需要加入一个辅助栈
将这些压入之后弹出的值滞后判断,先判断后一个
3- 依次判断,判断好之后将值弹出

def IsPopOrder_spd(pushlst, poplst_in):
    poplst = copy.deepcopy(poplst_in)
    stk = []
    for p in pushlst:
        stk.append(p)
        while stk and stk[-1] == poplst[0]:
            poplst.pop(0)
            stk.pop()
    return stk == []

22、从上到下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

22.1 思路

  • 思路

0- DLR
1- 如果是输出lst 需要一个辅助栈

22.2 解题

def preprint(tree, out = []):
    """
    需要一个辅助栈来存每次的节点值
    """
    out.append(tree.val)
    print(tree.val)
    if tree.left:
        preprint(tree.left, out)
    if tree.right:
        preprint(tree.right, out)
    return out

# 测试
from scc_function.Struct import BTree
t1 = BTree(1, left=BTree(2, left=BTree(6), right=BTree(8)),
           right=BTree(10, left=BTree(9), right=BTree(8)))
out_l = preprint(t1)
print(out_l)


"""
>>> out_l = preprint(t1)
1
2
6
8
10
9
8
>>> print(out_l)
[1, 2, 6, 8, 10, 9, 8, 1, 2, 6, 8, 10, 9, 8]
"""

23、二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

LRD (称为后根次序遍历)。

23.1 思路

  • 思路

0- LRD ,类似于判断是否是子树
1- 如果是输出lst 需要一个辅助栈

23.2 解题

class Solution:
    def VerifySquenceOfBST(self, lst):
        if len(lst) == 0:
            return False
        return self.Has_subtree(lst)

    def Has_subtree(self, lst):
        if len(lst) <= 2:
            return True
        flag = lst[-1]
        index = 0
        while lst[index] < flag:
               index += 1
        j = index
        while j < len(lst)-1:
            if lst[j] > flag:
                j += 1
            else:
                return False
        return self.Has_subtree(lst[:index]) and self.Has_subtree(lst[index:-1])

24、二叉树中和为某一值的路径

输入一颗二叉树的跟节点和一个整数, 打印出二叉树中节点的值的和为输入整数的所有路径。
路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意:在返回值的list中,数组长度大的数组靠前)

24.1 思路

  • 递归思路

1- 需要两个辅助栈,path = []记录一条路径, res = []汇总全部路径
2- 从头到尾遍历树,记录全部的路径,到底的时候和整数进行比较
3- 如果一致就加入 res

24.2 解题

def subPath(tree, number, path = [], res = []):
    if not tree:
        return []
    if not tree.left and not tree.right:
        if number == sum(path + [tree.val]):
            res.append(path + [tree.val])
    if tree.left:
        subPath(tree.left, number, path + [tree.val], res)
    if tree.right:
        subPath(tree.right, number, path + [tree.val], res)
    return sorted(res, key=len, reverse=True)


t_ = BTree(1
           , left=BTree(2, BTree(4), BTree(6))
           , right=BTree(3, BTree(1,BTree(2)), BTree(7))
)
subPath(t_, 7, path=[], res=[])

"""
>>> subPath(t_, 7, path=[], res=[])
[[1, 3, 1, 2], [1, 2, 4]]
>>>
"""

27、字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

27.1 思路

  • 递归思路

1- 需要两个辅助栈,path = ''记录一种顺序, res = []汇总全部顺序
2- 分为首字符和后续字符,求后续字符的全排序
3- 再将后续字符拆分成 首字符和后续字符

27.2 解题

class solution():
    def permutation(self, ss):
        if len(ss) <= 0:
            return ss 
        res = []
        self.helper(ss, res, '')
        return sorted(list(set(res)))
    
    def helper(self, ss, res, path):
        if not ss:
            res.append(path)
        else:
            for i in range(len(ss)):
                # 每次都去掉一个字母
                self.helper(ss[:i]+ss[i+1:], res, path+ss[i])

sov = solution()
sov.permutation('abc')
"""
>>> sov.permutation('abc')
['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
"""
  • ‘abc’ 递归示意
'abc' -> helper
    helper('bc', [], 'a') -> helper
        helper('c', [], 'ab') -> helper
            'abc' ->-> 进入 res
        helper('b', [], 'ac') -> helper
            'acb' ->-> 进入 res
        
    helper('ac', [], 'b') -> helper
        helper('c', [], 'ba') -> helper
            'bac' ->-> 进入 res
        helper('a', [], 'bc') -> helper
            'bca' ->-> 进入 res
            
    helper('ab', [], 'c') -> helper
        helper('b', [], 'ca') -> helper
            'cab' ->-> 进入 res
        helper('a', [], 'cb') -> helper
            'cba' ->-> 进入 res
最后用 set 和 sorted排序

28、数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

28.1 思路

  • 遍历

1- 列表遍历汇总到字典,并记录长度
2- 字典遍历,当数量大于长度一半则输出

28.2 解题

def MoreThanHalfNum_Solution(lst:list):
    n_p = 0
    num_dct = {}
    for i in lst:
        if i not in num_dct:
            num_dct[i] = 1
        else:
            num_dct[i] += 1
        n_p += 1

    for key, values in num_dct.items():
        if values > n_p//2:
            result = key
    return result

lst = [1,2,3,2,2,2,5,4,2]
MoreThanHalfNum_Solution(lst)

29、最小的K个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,

29.1 思路

  • 遍历

1- 列表遍历汇总到字典,并记录长度
2- 字典遍历,当数量大于长度一半则输出

29.2 解题

class solution():
    def tree_comp(self, lst, i, lst_len):
        """
        构建堆结构
        """
        top_i = i
        left_ = 2 * i + 1
        right_ = 2 * i + 2
        if (left_ < lst_len) and (lst[left_] < lst[top_i]):
            lst[left_], lst[top_i] = lst[top_i], lst[left_]
            self.tree_comp(lst, left_, lst_len)

        if (right_ < lst_len) and (lst[right_] < lst[top_i]):
            lst[right_], lst[top_i] = lst[top_i], lst[right_]
            self.tree_comp(lst, right_, lst_len)

    def build_minheap(self, lst, lst_len):
        """
        从下往上构建小顶堆
        """
        for i in range(lst_len//2, -1,-1):
            self.tree_comp(lst, i, lst_len)
            print(i, lst)
        print('\n')

    def heatsort(self, lst, lst_len, limit_ = None):
        """
        堆排序
        """
        # 构建小顶堆
        self.build_minheap(lst, lst_len)
        loop_ = lst_len if limit_ == None else  limit_
        lst_min4 = []
        lst_tmp = lst
        # 顶出顶部,然后后续进行堆结构构建
        for i in range(loop_):
            lst_min4.append(lst_tmp[0])
            lst_tmp = lst_tmp[1:]
            self.tree_comp(lst_tmp, 0, lst_len-1-i)
        return lst_min4
    
    def get_min4(self, lst, limit_):
        lst_len = len(lst)
        if limit_ > lst_len:
            return []
        if limit_ == lst_len:
            return lst
        return self.heatsort(lst, lst_len, limit_)


# 构建小顶堆
lst = [10, 5, 7, 11, 9, 6]
s = solution()
s.get_min4(lst, limit_ = 4)

"""
>>> s.get_min4(lst, limit_ = 4)
3 [5, 9, 6, 11, 10, 7]
2 [5, 9, 6, 11, 10, 7]
1 [5, 9, 6, 11, 10, 7]
0 [5, 9, 6, 11, 10, 7]

[5, 6, 7, 9]
"""

30、连续子数组的最大和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

30.1 思路

  • 遍历

1- 如果数组里所有的整数都是负数,那么选择最大的数即可,因为越累加越小
因为如果存在正数,其他均为负数这时候,最大就是这个正数,所以不会存在有正数,且连续几个和最大小于零的情况
2- 基于以上情况,可以做逐步累加,当前最大的值(同0比较),存储在loc_max
3- 将loc_max最大值存贮再glob_max中,即再全局最大中存储的必定是最大的值

30.2 解题

def maxSubArray(nums):
    if max(nums) < 0:
        return max(nums)
    
    loc_max, glob_max = 0, 0
    for i in nums:
        loc_max = max(0, loc_max + i)
        glob_max = max(loc_max, glob_max)
    return glob_max

maxSubArray([-2,1,-3,4,-1,2,1,-5,4])

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Scc_hy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值