剑指offer题解------Python语言实现

 

面试题3:数组中重复的数字

哈希法:时间复杂度O(n),空间复杂度O(n)

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        dic = dict()
        for item in numbers:
            if item not in dic:
                dic[item] = 1
            else:
                duplication[0] = item
                return True
        return False

面试题4:二维数组中的查找

当从二维数组的左上角或者右下角进行遍历时,一次只能排除一个数据,当右上角或者左下角开始遍历时,一次可以排除一行或者一列数据。所以我们从(0,n-1)处开始,小了往下,大了往左。

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        if not array:
            return False
        raws = len(array)
        columns = len(array[0])
        i = 0
        j = columns -1
        while i < raws and j >= 0: # 在整个二维数组中进行寻找
            if array[i][j] == target:
                return True
            elif array[i][j] > target:
                j -= 1
            else:
                i += 1
        return False # 没有找到

面试题5:替换空格

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        return '%20'.join(s.split(' '))
        # return s.replace(' ', '%20') #或者调用函数

面试题6:从尾到头打印链表

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def __init__(self):
        self.result = []
    def printListFromTailToHead(self, listNode):
        if listNode: # 递归实现系统栈 只能使用if使用while会造成死循环
            self.printListFromTailToHead(listNode.next)
            self.result.append(listNode.val)
        return self.result

面试题7:重建二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        if not pre:
            return
        t = pre[0]
        root = TreeNode(t)
        i = tin.index(t)
        root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i])
        root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:])
        return root

面试题8:二叉树的下一个结点

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        if not pNode:
            return
        if pNode.right: # 如果该结点有右孩子
            z = pNode.right
            while z.left: # 判断是否有左孩子,如果有找到最左边的
                z = z.left
            return z
        # 以下代码特别容易出错,请注意
        while pNode.next :
            if pNode.next.left == pNode: # 如果当前结点是其父节点的左结点
                return pNode.next # 直接将其父节点返回
            pNode = pNode.next # 该结点为父节点的右结点,找到以该子树为左节点的父节点
        return 

面试题9:用两个栈实现队列

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        self.stack1.append(node)
    def pop(self):
        if not self.stack1 and not self.stack2:
            return
        elif self.stack2:
            return self.stack2.pop()
        else:
            while self.stack1:
                tmp = self.stack1.pop()
                self.stack2.append(tmp)
            return self.stack2.pop()

面试题10:斐波那契数列

求斐波那契数列的第n项

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n < 2:
            return n 
        lst = [0,1]
        for _ in range(n-1):
            lst.append(lst[-1]+lst[-2])
        return lst[-1]

跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 
dp[n]=dp[n−1]+dp[n−2]dp[n]=dp[n−1]+dp[n−2]

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        '''
        n = 1 : 1 
        n = 2 : 1+1 = 2
        n = 3 : f[n-2]+f[n-1]
        '''
        if number == 1 :
            return 1
        if number == 2:
            return 2
        tmp = [1,2]
        for i in range(number - 2):
            tmp.append(tmp[-1]+tmp[-2])
        return tmp[-1]

变态跳台阶

因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
跳2级,剩下n-2级,则剩下跳法是f(n-2)
所以f(n)=f(n-1)+f(n-2)+...+f(1)
因为f(n-1)=f(n-2)+f(n-3)+...+f(1)

所以f(n)=2*f(n-1)

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number == 0:
            return 0
        if number ==1:
            return 1
        else:
            return 2 * self.jumpFloorII(number - 1)

或者直接套用数学归纳出来的公式 2 **(n-1) 

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number == 0:
            return 0
        else:
            return 2 **(number - 1)

矩形覆盖 
可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

剑指offer题解------Python语言实现_第1张图片

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here

        if number<=2:
            return number
        dp = [1,2]
        for i in range(number-2):
            dp.append(dp[-1]+dp[-2])
        return dp[-1]

面试题11:旋转数组的最小数字

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, array):
        if not array:
            return
        n = len(array)
        low = 0
        high = n - 1
        while low <= high:
            mid = (low + high) // 2
            if array[mid] > array[mid+1]: # 二分查找要查找的目标
                return array[mid+1]
            elif array[mid] > array[low]:
                low = mid
            else:
                high = mid

面试题15:二进制中1的个数

对于负数,最高位为1,而负数在计算机是以补码存在的,往右移,符号位不变,符号位1往右移,最终可能会出现全1的情况,导致死循环。与0xffffffff相与,就可以消除负数的影响

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        if n < 0: # python没有无符号移动,负数需要处理下
            n = n & 0xffffffff 
        return bin(n).count('1')

面试题16:数值的整数次方

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        flag = 0 # 判断是否为负数的标志
        if base == 0 and exponent == 0:
            return 'Input error'
        elif base == 0:
            return 0
        elif exponent == 0:
            return 1
        elif exponent < 0:
            flag = 1 # 如果幂为负数,则将标志置为1
            exponent = -exponent
        i = 1 
        result = 1
        while i <= exponent:
            result *= base
            i += 1
        if flag == 1:
            return 1/result
        else:
            return result

面试题18:

题目二:删除链表中重复的结点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        if not pHead:
            return
        head = ListNode(0)
        head.next = pHead
        pre = head
        cur = head.next
        while cur and cur.next:
            if cur.val == cur.next.val:
                while cur.next and cur.val == cur.next.val:
                    cur.next = cur.next.next
                pre.next = cur.next
                cur = pre.next
            else:
                pre = cur
                cur = cur.next
        return head.next

 面试题20:表示数值的字符串

# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        if not s:
            return 
        sign, point, hasE = False, False, False
        for i in range(len(s)):
            if s[i].lower() == 'e':   # 判断e的存在及个数
                if hasE:              # 有两个e
                    return False
                if i == len(s)-1:     # e位于字符串最后
                    return False
                hasE = True
            elif s[i] == '+' or s[i] == '-':
                if sign and s[i-1].lower() != 'e': # + -第二次出现 但并未位于e之后
                    return False
                # 如果 + - 第一次出现且出现于字符串中间但并位于e之后
                if not sign and i > 0 and s[i-1].lower() != 'e': 
                    return False
                sign = True
            elif s[i] == '.':         # 两个小数点或小数点与e不能同时出现
                if hasE or point: 
                    return False
                point = True
            elif ord(s[i]) < ord('0') or ord(s[i]) > ord('9'): # 如果当前字符不是一个数字
                return False
        return True

面试题21:调整数组顺序使奇数位于偶数前面

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        arr1 = []
        arr2 = []
        for num in array:
            if num % 2 == 1:
                arr1.append(num)
            else:
                arr2.append(num)
        arr1.extend(arr2)
        return arr1

面试题22:链表中倒数第k个结点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        if not head or not head.next:
            return
        slow = head
        fast = head
        for _ in range(k):
            if fast:
                fast = fast.next
            else:
                return
        while fast:
            fast = fast.next
            slow = slow.next
        return slow

面试题24:链表中环的入口结点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        def isloop(pHead):
            if not pHead:
                return
            slow = pHead
            fast = pHead
            while fast and fast.next:   # 对于有环的链表来说 这个条件一直满足
                slow = slow.next
                fast = fast.next.next
                if slow == fast:
                    return slow
            return  # 如果没环直接退出
        end = isloop(pHead)
        if not pHead or not end:
            return
        first = pHead  
        while end != first: # 2(a+b)=a+b+c+b
            first = first.next
            end = end.next
        return first

面试题24:反转链表

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        pre = None
        cur = pHead
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
# 通过设置虚拟头结点进行删除
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        if not pHead or not pHead.next:
            return pHead
        head = ListNode(0)
        head.next = pHead
        pre = head.next
        cur = head.next.next
        while cur:
            pre.next = cur.next
            cur.next = head.next
            head.next = cur
            cur = pre.next
        return head.next

面试题25:合并两个排序的链表

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        head = ListNode(0)
        cur = head
        while pHead1 and pHead2:
            if pHead1.val <= pHead2.val:
                cur.next = pHead1
                cur = cur.next
                pHead1 = pHead1.next
            else:
                cur.next = pHead2
                cur = cur.next
                pHead2 = pHead2.next
        if pHead1:  # 如果还有剩余,将他们继续添加到cur后边
            cur.next = pHead1
        if pHead2:
            cur.next = pHead2
        return head.next

面试题26:树的子结构

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSubtree(self,a,b): # 找到相等的根节点后 判断是否为子树
        if not b: # ①判断B是否匹配完了,如果匹配完了说明为子结构
            return True
        if not a or a.val != b.val: # ②如果A匹配完了,或者A的值和B和值不等,直接返回False
            return False # ③如果当前点相同,那同时看一下左子树和右子树的情况
        return self.isSubtree(a.left, b.left) and self.isSubtree(a.right, b.right)
        
    def HasSubtree(self, pRoot1, pRoot2):
        if not pRoot1 or not pRoot2:
            return False # 从根节点开始判断 判断左子树,判断右子树
        return self.isSubtree(pRoot1,pRoot2)or self.HasSubtree(pRoot1.left,pRoot2) or self.HasSubtree(pRoot1.right,pRoot2)

面试题27:二叉树的镜像

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    # 二叉树的本质就是递归,将完整的二叉树先缩小规模看成只有两个叶结点的子二叉树
    # 其顺序与后序遍历相同 先两个子节点 然后根结点
    def Mirror(self, root):
        if root == None:
            return 
        self.Mirror(root.left)
        self.Mirror(root.right)
        
        tmp = root.left
        root.left = root.right
        root.right = tmp
        return root

面试题28:对称的二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def is_mirror(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 self.is_mirror(left.left, right.right) and self.is_mirror(left.right, right.left)
    
    def isSymmetrical(self, pRoot):
        if not pRoot:
            return True
        return self.is_mirror(pRoot.left, pRoot.right)

面试题29:顺时针打印矩阵

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        res = []
        while matrix:                # 只要矩阵不为空就一直循环
            res += matrix.pop(0)     # 方向:上
            if matrix and matrix[0]: # 方向:右 第二个条件 确保是一个二维数组
                for row in matrix:
                    res.append(row.pop())
            if matrix:               # 方向:下
                res += matrix.pop()[::-1]
            if matrix and matrix[0]: # 方向:左
                for row in matrix[::-1]:
                    res.append(row.pop(0))
        return res

面试题30:包含min函数的栈

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
        
    def push(self, node):
        self.stack1.append(node)
        if not self.stack2 or node <= self.stack2[-1]:
            self.stack2.append(node)
            
    def pop(self):
        if self.stack2[-1] == self.stack1[-1]:
            self.stack2.pop()
        self.stack1.pop()
        
    def top(self):
        return self.stack1[-1]
    
    def min(self):
        if self.stack2:
            return self.stack2[-1]
        return

面试题31:栈的压入、弹出序列

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        stack = []
        pushLen = len(pushV)
        popLen = len(popV)
        if pushLen != popLen:
            return False
        pushIndex = 0
        popIndex = 0
        while pushIndex < pushLen:
            stack.append(pushV[pushIndex])
            pushIndex += 1
            while len(stack) != 0 and stack[-1] == popV[popIndex]:
                stack.pop()
                popIndex += 1
        return len(stack) == 0 and pushIndex == popIndex

面试题32:

题目一:从上往下打印二叉树 

class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        res = []
        if root is None:
            return res
        queue = [root]
        while queue:
            item = queue.pop(0)
            res.append(item.val)
            if item.left:
                queue.append(item.left)
            if item.right:
                queue.append(item.right)
        return res

题目二:把二叉树打印成多行

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        if pRoot is None:
            return []
        queue = [pRoot]
        result = []
        while queue:
            tmp = []
            n = len(queue)
            for _ in range(n):
                node = queue.pop(0)
                tmp.append(node.val)
                if node.left:  # -_-|| 调试了好多次,原来是用成了汉字冒号!!!
                    queue.append(node.left) # 牛客也没有提示啊!!!!!
                if node.right:
                    queue.append(node.right)
            result.append(tmp)
        return result

题目三:按之字形顺序打印二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        if pRoot is None:
            return []
        queue = [pRoot]
        result = []
        i = 1
        while queue:
            n = len(queue)
            tmp = []
            for _ in range(n):
                m = queue.pop(0)
                tmp.append(m.val)
                if m.left:
                    queue.append(m.left)
                if m.right:
                    queue.append(m.right)
            if i%2 == 0:
                tmp = tmp[::-1]
            i += 1
            result.append(tmp)
        return result

面试题33:二叉搜索树的后序遍历序列

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        if len(sequence) == 0:
            return False
        root = sequence[-1] # 最后一个为根节点
        n = len(sequence)-1 # 最后一个元素的索引
        i = 0
        while i < n: # 找到第一个大于跟结点的位置
            if sequence[i] > root:
                break
            i += 1 
        j = i
        while j < n: # 判断右子树的元素是否都比根节点大
            if sequence[j] < root:
                return False
            j += 1
        left = True
        right = True
        if i != 0: # 避免 i = 0
            left = self.VerifySquenceOfBST(sequence[:i])
            right = self.VerifySquenceOfBST(sequence[i:])
        return left and right

面试题34:二叉树中和为某一值的路径

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def __init__(self):
        self.sums = 0    # 存放当前和
        self.rode = []   # 当前路径
        self.res = []    # 二维结果列表
    def FindPath(self, root, expectNumber):
        if not root or not expectNumber:
            return []
        self.sums += root.val
        self.rode.append(root.val)
        if not root.left and not root.right and self.sums == expectNumber:
            # 注意此处是self.rode[:] 不加[:] 直接使用变量名会返回空的二维列表
            # 可变对象与不可变对象的复制  隐藏很深的bug!!
            self.res.append(self.rode[:])  # 这里也不能直接return 因为后边还要逐个弹出
        self.FindPath(root.left, expectNumber)
        self.FindPath(root.right, expectNumber)
        self.sums -= root.val
        self.rode.pop()
        return self.res

面试题35:复杂链表的复制

剑指offer题解------Python语言实现_第2张图片

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        if not pHead:
            return None
        # 第一步:复制节点在原节点之后
        pCur = pHead
        while pCur:
            node = RandomListNode(pCur.label)
            node.next = pCur.next
            pCur.next = node
            pCur = node.next
        # 第二步:复制random节点
        pCur = pHead
        while pCur:
            if pCur.random:
                pCur.next.random = pCur.random.next
            pCur = pCur.next.next
        # 第三步:将新旧链表分离
        pCur = pHead
        head = pHead.next
        cur = head
        while pCur:
            pCur.next = pCur.next.next
            if cur.next:
                cur.next = cur.next.next
            cur = cur.next
            pCur = pCur.next
        return head

 

面试题36:二叉搜索树与双向链表

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.head = None
        self.end = None
    def Convert(self, root):
        if not root:
            return
        self.Convert(root.left)
        root.left = self.end
        if self.end:
            self.end.right = root
        else:
            self.head = root
        self.end = root
        self.Convert(root.right)
        return self.head

面试题37:序列化二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Serialize(self, root):
        def pre_order(root):
            if not root:
                result.append('#')
                return
            result.append(str(root.val))
            pre_order(root.left)
            pre_order(root.right)
        result = []
        pre_order(root)
        return ' '.join(result)
    
    def Deserialize(self, s):
        vals = iter(s.split())
        def pre_order():
            val = next(vals)
            if val == '#':
                return None
            root = TreeNode(int(val))
            root.left = pre_order()
            root.right = pre_order()
            return root
        return pre_order()

 

面试题38:字符串的排列

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        if not ss:         # 递归出口
            return []
        n = len(ss)
        if n == 1:
            return [ss]
        
        res = []
        for i in range(n):  # 逐渐缩小问题的规模
            tmp = self.Permutation(ss[:i]+ss[i+1:]) # 对除当前字符外的其他字符进行全排列
            for j in tmp:
                res.append(ss[i]+j)   # 将该字符与全排列的其余字符做拼接
        return sorted(list(set(res))) # 对拼接后的字符 去重 排序

 

面试题39:数组中出现次数超过一半的数字

哈希法:

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        if not numbers:
            return
        n = len(numbers)
        dic = dict()
        for num in numbers:
            if num not in dic:
                dic[num] = 1
            else:
                dic[num] += 1
            if dic[num] > n/2:
                return num
        return 0  # 如果没有则返回0

 

面试题40:最小的k个数

# -*- coding:utf-8 -*-
################## 八大排序算法实现最小的K个数 #######################
class Solution:
    # 选择排序
    def select_sort(self, tinput):
        n = len(tinput)
        for i in range(n):
            min_i = i
            for j in range(i+1, n):
                if tinput[min_i] > tinput[j]:
                    min_i = j
            tinput[i], tinput[min_i] = tinput[min_i], tinput[i]
        return tinput

    # 冒泡排序(优化版)
    def bubble_sort(self, tinput):
        n = len(tinput)
        for i in range(n)[::-1]:
            count = 0
            for j in range(i):
                if tinput[j] > tinput[j+1]:
                    tinput[j], tinput[j+1] = tinput[j+1], tinput[j]
                    count += 1
            if count == 0:
                return tinput
        return tinput
    
    # 插入排序
    def insert_sort(self, tinput):
        n = len(tinput)
        for i in range(1, n):
            j = i
            while j >0:
                if tinput[j] < tinput[j-1]:
                    tinput[j], tinput[j-1] = tinput[j-1], tinput[j]
                    j -= 1
                else:
                    break
        return tinput
    
    # 希尔排序
    def shell(self,tinput):
        n = len(tinput)
        gap = n // 2   # 使用不同的gap对数组进行预排序
        while gap >0:
            for i in range(gap, n): # 对每一个gap都需要对gap后的每一个关键字进行插入排序
                j = i # 初始化一个指针
                while j >= gap: 
                    if tinput[j] < tinput[j - gap]: # 对一个gap进行插入排序
                        tinput[j], tinput[j - gap] = tinput[j - gap], tinput[j]
                        j -= gap  # 一个gap的前一个关键字
                    else:
                        break
            gap = gap // 2
        return tinput
    
    # 快速排序
    def quick_sort(self, tinput,left, right):
        if left >= right:      # 递归出口
            return tinput
        i = left
        j = right
        tmp = tinput[i]        # 选当前序列的第一个关键字为枢纽
        while i < j:  # 完成一次排序 将小于tmp的值放到tmp的左边,大于tmp的值放到tmp的右边
            while i < j and tinput[j] >= tmp: # 从右往左扫描,找到一个小于tmp的关键字
                j -= 1
            tinput[i] = tinput[j]
            while i < j and tinput[i] <= tmp: # 从左往右扫描,找到一个大于tmp的关键字
                i += 1
            tinput[j] = tinput[i]
        tinput[i] = tmp        # 一次循环结束后,i = j
        self.quick_sort(tinput,left, i-1)
        self.quick_sort(tinput,i+1, right)
        return tinput
    
    # 归并排序
    def merge_sort(self,tinput):
        def merge(list1, list2):
            i, j = 0, 0
            n1 = len(list1)
            n2 = len(list2)
            result = []
            while i < n1 and j < n2:
                if list1[i] <= list2[j]:
                    result.append(list1[i])
                    i += 1
                else:
                    result.append(list2[j])
                    j += 1
            if list1:
                result.extend(list1[i:])   # 注意这里是extend而不是append
                #result += list1[i:]       # 这样写也可以 [] + [] ==> [].entend([])
            if list2:
                result.extend(list2[j:])
            return result
        
        n = len(tinput)
        if n <=1:
            return tinput
        tmp = n/2
        left = self.merge_sort(tinput[:tmp])
        right = self.merge_sort(tinput[tmp:])
        return merge(left, right)
         
        
    # 堆排序
    def  heap_sort(self,lists):
        def  adjust_heap(lists, i, size): # 输入参数:数组,调整节点位置,数组长度
            lchild = 2 * i + 1          # 当前结点左孩子的索引
            rchild = 2 * i + 2          # 当前结点右孩子的索引
            maxs = i                    
            if  i < size // 2:          # 如果当前结点为非叶子节点
                if  lchild < size and lists[lchild] > lists[maxs]:
                    maxs = lchild
                if  rchild < size and lists[rchild] > lists[maxs]:
                    maxs = rchild
                if  maxs != i:  # 如果当前结点满足大顶堆要求不交换,不满足进行交换并对其孩子结点进行调整
                    lists[maxs], lists[i] = lists[i], lists[maxs]
                    adjust_heap(lists, maxs, size) # 对交换后的孩子结点进行调整
                    
        def  build_heap(lists, size):   # 输入参数为:数组,数组长度
            for  i  in  range(size//2)[::-1]: # 对每一个非叶子节点进行调整
                adjust_heap(lists, i, size)
                
        size = len(lists)
        build_heap(lists, size)         # 对当前数组,建一个大顶堆
        for  i  in  range(size)[::-1]:  # 依次将第i大的元素放到第i个位置
            lists[0], lists[i] = lists[i], lists[0]
            adjust_heap(lists, 0, i)    # 对堆顶位置进行调整 
        return lists
    
    # 基数排序
    def radix(self, tinput):
        if not tinput:
            return []
        k = len(str(max(tinput)))
        bucket = [[] for i in range(10)]
        for i in range(k):
            for num in tinput:
                bucket[num/(10**i)%10].append(num)
            del tinput[:]
            for z in bucket:
                tinput += z
                del z[:]
        return tinput
    
    def GetLeastNumbers_Solution(self, tinput, k):
        left = 0
        right = len(tinput)-1
        #tinput = self.select_sort(tinput)
        #tinput = self.insert_sort(tinput)
        #tinput = self.bubble_sort(tinput)
        #tinput = self.shell(tinput)
        #tinput = self.quick_sort(tinput,left,right)
        #tinput = self.radix(tinput)
        #tinput = self.heap_sort(tinput)
        tinput = self.merge_sort(tinput)
        n = len(tinput)
        if k<=n:
            return tinput[:k]
        else:
            return []

 

 

面试题41:数据流中的中位数

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.arr = []
    def Insert(self, num):
        self.arr.append(num)
    def GetMedian(self,x):
        self.arr.sort()
        n = len(self.arr)
        m = n // 2
        if n % 2 == 0:
            return (self.arr[m] + self.arr[m-1])/2.0
        return self.arr[m]

 

面试题42:连续子数组的最大和

从前往后加,加入新元素后如果和大于零则有用,小于零将 sub_sum置为零则重新开始记录

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        max_sum = 0
        sub_sum = 0
        for num in array:
            sub_sum += num
            if sub_sum < 0:
                sub_sum = 0
            if sub_sum > max_sum:
                max_sum = sub_sum
        if max_sum == 0:
            return max(array)
        return max_sum

 

面试题43:1-n整数中1出现的次数

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        a = ''
        for i in range(1, n+1):
            a += str(i)
        return a.count("1")

 面试题45:把数组排成最小的数

 

# -*- coding:utf-8 -*-
# python3的sort方法没有了cmp参数,需要对其key参数进行以下处理
# import functools.cmp_to_key
# key = cmp_to_key(self.cmp)

class Solution:
    def cmp(self, a, b):
        return 1 if a+b > b+a else -1
    def PrintMinNumber(self, numbers):
        string = map(str, numbers) # string = [str(num) for num in numbers]
        string.sort(self.cmp)
        return ''.join(string)

面试题:字符流中第一个不重复的元素

# -*- coding:utf-8 -*-
class Solution:
    # 返回对应char
    def __init__(self):
        self.s = '' # 用于记录加入的总字符串
        self.dic = dict() # 用于统计单个字符串出现的次数
    def FirstAppearingOnce(self):
        for i in self.s:
            if self.dic[i] == 0:
                return i
        return '#'
    def Insert(self, char): # 用于添加单个字符
        self.s += char 
        if char not in self.dic:
            self.dic[char] = 0
        else:
            self.dic[char] += 1

面试题49:丑数 

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        if index <= 1: 
            return index
        res = [1] * index
        i2, i3, i5 = 0, 0, 0     # 声明三个索引,可看做是存放排序丑数分别乘以2 3 5的三个队列
        for i in range(1, index):# 循环一次产生一个大于已有序丑数的最小丑数
            num2 = res[i2]*2     # 产生最有可能的三个丑数
            num3 = res[i3]*3
            num5 = res[i5]*5
            res[i] = min(num2, min(num3, num5)) # 在产生的三个丑数当中选取最小的一个
            if res[i] == num2: 
                i2 += 1
            if res[i] == num3: 
                i3 += 1
            if res[i] == num5: 
                i5 += 1
        return res[-1]

面试题50:第一个只出现一次的字符

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        dic = dict()
        for tmp in s:
            if tmp not in dic:
                dic[tmp] = 0
            else:
                dic[tmp] += 1
        for i in range(len(s)):
            if dic[s[i]] == 0:
                return i
        return -1

 

面试题52:两个链表的第一个公共结点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        if not pHead1 or not pHead2:
            return
        p, q = pHead1, pHead2
        len1, len2 = 0, 0
        while p:
            len1 += 1
            p = p.next
        while q:
            len2 += 1
            q = q.next
        if len1 > len2:
            p, q = pHead1, pHead2
        else:
            p, q = pHead2, pHead1
        for i in range(abs(len1-len2)):
            p = p.next
        while p != q:
            p = p.next
            q = q.next
        return p 
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        if not pHead1 or not pHead2:
            return
        dic = dict() 
        while pHead1: # 将该链表放入字典中(哈希表)查找时间复杂度为O(1)
            dic[pHead1] = 0
            pHead1 = pHead1.next
        while pHead2:
            if pHead2 in dic:
                return pHead2
            pHead2 = pHead2.next
        return

面试题53:数字在排序数组中出现的次数

# -*- coding:utf-8 -*-
class Solution:
    def binary_search(self, data, k):
        if not data:
            return
        n = len(data)
        left = 0
        right = n - 1
        while left <= right:
            mid = (left + right) // 2
            if data[mid] == k:
                return mid
            elif data[mid] > k:
                right = mid - 1
            else:
                left = mid + 1
        return left
    def GetNumberOfK(self, data, k):
        if not data:
            return 0
        return self.binary_search(data, k+0.5) - self.binary_search(data, k-0.5)

 

面试题55:

题目一 二叉树的深度:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        if pRoot == None: # 递归出口
            return 0
        return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

 

题目二 平衡二叉树:

如果直接从上向下计算树的深度,判断是否满足平衡二叉树的定义,会多次重复遍历下层结点,增加了不必要的开销。

如果改为从下往上遍历,如果子树是平衡二叉树,则返回子树的高度;如果发现子树不是平衡二叉树,则直接停止遍历,这样至多只对每个结点访问一次。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def get_depth(self, p):
        if not p:
            return 0
        left = self.get_depth(p.left)    # 当前结点左子树的深度 
        if left == -1:                   # 左子树不是平衡二叉树
            return -1
        right = self.get_depth(p.right)  # 当前结点右子树的深度
        if right == -1:                  # 右子树不是平衡二叉树
            return -1
        if abs(left - right) > 1:        # 如果以当前结点为根节点的树不是平衡二叉树
            return -1
        else:
            return max(left, right) + 1  # 当前子树为平衡二叉树,返回当前子树的深度
    
    def IsBalanced_Solution(self, p):
        return self.get_depth(p) != -1

 另一种解法:复杂度较高

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def treeDepth(self, root):
        if root == None:
            return 0
        return max(self.treeDepth(root.left),self.treeDepth(root.right)) + 1
    
    def IsBalanced_Solution(self, pRoot):
        if pRoot == None:
            return True
        return abs(self.treeDepth(pRoot.left) - self.treeDepth(pRoot.right))<= 1

 

面试题54:二叉搜索树的第k个结点

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def KthNode(self, pRoot, k):
        result = []
        # 二叉排序树的顺序与该二叉树的中序遍历顺序相同
        def in_order(pRoot): # 注意类方法内部的函数不需要 self
            if pRoot == None:
                return
            in_order(pRoot.left)
            result.append(pRoot) # 将中序遍历的结果放入一个数组中
            in_order(pRoot.right)
        in_order(pRoot)
        if k == 0 or k > len(result):
            return
        return result[k-1] # 取出第k个结点

空间复杂度较小的另一种方案:

class Solution:
    # 返回对应节点TreeNode
    def __init__(self):
        self.num = 0
        self.res = [] # 因为递归嵌套了很多函数 不能直接将结果return 
    def KthNode(self, pRoot, k):
        if not pRoot or k < 1:
            return
        self.KthNode(pRoot.left, k)
        self.num += 1
        if self.num == k:
            self.res.append(pRoot)   # 将结果暂存在一个列表中   
        self.KthNode(pRoot.right, k)
        if self.res:  
            return self.res[0]     

面试题57:和为S的两个数字

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        min_mul = float('inf') # 将初始最小值设置为无穷大,负无穷:-float('inf') 或 float('-inf'),其中,inf 均可以写成 Inf
        min_i = 0
        for i in array:
            if tsum - i in array and i * (tsum - i) < min_mul:
                min_i = i
                min_mul = i * (tsum - i)
        if min_mul == float('inf'):
            return []
        a = [min_i, tsum - min_i]
        sorted(a)
        return a[0], a[1]

# 方法二
# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        dic = dict()
        result = []
        min_res = 999999999
        min_lst = []
        for num in array:
            dic[num] = num
        for i in array:
            if tsum - i in dic:
                result.append([i, tsum - i])
        for lst in result:
            if lst[0]*lst[1] < min_res:
                min_res = lst[0]*lst[1]
                min_lst = lst
        return sorted(min_lst)

题目二:和为S的连续正数序列

 

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, s):
        i, j = 1, 2 
        res = []
        while i < (s+1)//2:         # 较小的值增加到该值结束
            tmp = sum(range(i,j+1))   # 对i-j之间的序列求和
            if tmp < s:             # 当前序列和较小 对j加一
                j += 1
            elif tmp > s:           # 当前序列和较大对i加一
                i += 1
            else:                     # tmp = s时
                res.append(range(i, j+1))
                j += 1                # 或者i += 1 制造新的不相等 避免死循环
        return res

面试题58:翻转字符串

题目一:

# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        lst = s.split(' ')[::-1]
        return ' '.join(lst) # 传入可迭代对象,以‘ ’进行拼接

 

题目二:左旋转字符串

# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here
   
        return s[n:] + s[:n]

 

面试题:数组中只出现一次的数字

# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        sum = 0
        for i in array:
            sum ^= i 
        for i in array:
            if i^sum in array:
                return [i, i^sum]

  面试题61:扑克牌中的顺子

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        if not numbers:
            return False
        numbers.sort()                # 第一步:先对数组排序
        zero_num = numbers.count(0)   # 第二步:计算数组中大小王的个数
        for i in range(len(numbers)-1):
            if numbers[i] != 0:
                if numbers[i] == numbers[i+1]: # 出现对子直接返回
                    return False
                zero_num = zero_num - (numbers[i+1] - numbers[i])+1 #第三步:弥补空缺数
                if zero_num < 0:
                    return False
        return True

 面试题66:构建乘积数组

剑指offer题解------Python语言实现_第3张图片

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        if not A:
            return []
        n = len(A)
        B = [1]*n
        for i in range(1, n):     # 计算A正三角并将值赋给B的相应位置
            B[i] = B[i-1] * A[i-1] 
        temp = 1              # 倒三角第一个元素初始化为1
        for i in range(n-2, -1, -1):
            temp *= A[i+1]    # 计算倒三角
            B[i] *= temp      # 得到最终结果
        return B

 

面试题67:把字符串转换成整数 

# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        if not s:
            return 0
        res = 0
        flag = 1
        for i in range(len(s)):
            if i == 0 and s[i] == '+':
                continue
            elif i == 0 and s[i] == '-':
                flag = -1
                continue
            n = ord(s[i]) - ord('0')  # 计算当前字符所对应数字的ASC码
            if n>=0 and n<=9:
                res = 10*res + n
            else:
                return 0
        return res * flag

 

你可能感兴趣的:(数据结构与算法)