《剑指offer》python实现

配合Online Judge刷题,体验更佳!剑指offer_编程题_牛客网

1. 二维数组中的查找

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        i = len(array) - 1
        j = 0
        while i >= 0 and j < len(array[0]):
            if target == array[i][j]:
                return True
            elif target > array[i][j]:
                j += 1
            else:
                i -= 1
        return False

思路

将这个矩阵理解为一块切斜的平面,左低右高,上低下高。巧妙的将查找起点设置在左下角(或者右上角),这样保证查找方向唯一。

2. 替换空格

题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are
Happy.则经过替换之后的字符串为We%20Are%20Happy。

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        new_s = ''
         
        for i in s:
            if i != ' ':
                new_s += i
            else:
                new_s += '%20'
        return new_s

思路
使用python 字符串连接的语法,实现得简单了。也可以先计算新字符串的长度,然后通过下标索引填充字符。

3. 从尾到头打印链表

题目描述

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

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

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        stack = []
        while listNode:
            stack.append(listNode.val)
            listNode = listNode.next
        resultArray = []
        while stack:
            resultArray.append(stack.pop())
        return resultArray

思路
使用了两个列表,第一个列表顺序装入链表节点,第二个列表翻转第一个列表。

4. 重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

# -*- 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 None
        for index in range(len(tin)):
            if tin[index] == pre[0]:
                break
        left_tin = tin[:index]
        right_tin = tin[index+1:]
        left_pre = pre[1:index + 1]
        right_pre = pre[index + 1:]
        rootNode = TreeNode(pre[0])
        rootNode.left = self.reConstructBinaryTree(left_pre, left_tin)
        rootNode.right = self.reConstructBinaryTree(right_pre, right_tin)
        return rootNode

思路
利用如下规则,递归地切分左右子树的前序和中序遍历列表。
1、前序遍历的第一个数字是根节点;
2、中序遍历,根节点左边的数字属于左子树,,右边的数字属于右子树。
3、前序和中序遍历,左子树的数字在右子树的前面。

5. 用两个栈实现队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        # write code here
        self.stack1.append(node)
    def pop(self):
        # return xx
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop(-1))
        return self.stack2.pop(-1)

思路
只在stack2为空时,才把stack1的元素一次性倒入stack2。

6. 旋转数组的最小数字

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        tmp = 0
        for i in rotateArray:
            if i < tmp:
                return i
            else:
                tmp = i
        return 0

思路
比较相邻元素,查找。


7. 斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。 n<=39

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.fibonacci_dict = {}
    def Fibonacci(self, n):
        # write code here
        if self.fibonacci_dict.has_key(n):
            return self.fibonacci_dict[n]
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            value = self.Fibonacci(n-1) + self.Fibonacci(n-2)
            self.fibonacci_dict[n] = value
            return value

思路
递归。因为运行超时,这里加了个键值对缓存。


8. 跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloor(self, number):
        # write code here
        j1 = 1
        j2 = 2
        if number == 1:
            return j1
        elif number == 2:
            return j2
        for _ in range(number-2):
            j2, j1 = j1+j2, j2
        return j2

思路
跟斐波那契数列一样。


9. 变态跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

# -*- coding:utf-8 -*-
class Solution:
    def jumpFloorII(self, number):
        # write code here
        if number == 1:
            return 1
        elif number ==2:
            return 2
        n_list = [1,2]
        for _ in range(number-2):
            n_list.append(sum(n_list)+1)
        return n_list[-1]

思路
规律是n 级台阶的跳法是1、2、…、n-1 级台阶跳法的和,再加上1.


10. 矩形覆盖

题目描述

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

# -*- coding:utf-8 -*-
class Solution:
    def rectCover(self, number):
        # write code here
        f1 = 1
        f2 = 2
        if number == 1:
            return f1
        elif number == 2:
            return f2
        elif number ==0:
            return 0
        for _ in range(number-2):
            f2, f1  = f1+f2, f2
        return f2 

思路
跟跳台阶一样,本质上都是斐波那契数列。


11. 二进制中1的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        if n < 0:
            n = 2**31+n
            count +=1
        while n != 0:
            count += (n%2)
            n = n//2
        return count

思路
负数的补码,其实是2**31 减去负数绝对值之后的正数的二进制码,最高位是1以标记为负数。


12. 数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        if exponent < 0:
            tmp_exp = -exponent
        else:
            tmp_exp = exponent

        result = 1

        if tmp_exp == 1:
            result = base

        tmp_base = base
        while tmp_exp > 1:
            if tmp_exp%2 == 1:
                result *= tmp_base
            result *= tmp_base**2
            tmp_exp = tmp_exp //2
            tmp_base = base**2

        if exponent < 0:
            result = 1.0/result
        return result

思路
找到循环的模式,例如
n 11 = n 2 ∗ 5 ∗ n = ( n 2 ) 2 ∗ 2 ∗ n 2 ∗ n . n^{11}= n^{2*5}*n={(n^{2})}^{2*2}*n^{2}*n. n11=n25n=(n2)22n2n.


13. 调整数组顺序使奇数位于偶数前面

题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        result_array = array[:]
        length = len(array)
        for i in range(length):
            for j in range(length-1-i):
                if result_array[j]%2 ==0 and result_array[j+1]%2 ==1:
                    tmp = result_array[j]
                    result_array[j] = result_array[j+1]
                    result_array[j+1] = tmp
        return result_array

思路
借用了冒泡排序,只不过是元素交换条件换成了:相邻两个元素,左边偶数右边奇数。冒泡排序是稳定性排序,相等的元素相对位置不变(这里的相等的含义是两个奇数是相等的,或者两个偶数是相等的)。


14. 链表中倒数第k个结点

题目描述

输入一个链表,输出该链表中倒数第k个结点。

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

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if not head:
            return None
        node = head
        node_list = []
        while node:
            node_list.append(node)
            node = node.next
        if k > len(node_list) or k < 1:
            return None
        else:
            return node_list[-k]

思路
遍历链表,然后把节点按顺序放在列表里,返回倒数第k个元素。

15. 反转链表

题目描述

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

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead:
            return None
        p1 = pHead
        p = pHead.next
        p1.next = None
        while p:
            p2 = p.next
            p.next = p1
            p1 = p
            p = p2
        return p1

思路
设置3个相邻元素的指针,遍历链表,挨个的改变节点的next。

16. 合并两个排序的链表

题目描述

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

# -*- 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
        pHead = p = ListNode(0)
        while pHead1 or pHead2:
            if not pHead1:
                p.next = pHead2
                break
            if not pHead2:
                p.next = pHead1
                break
            if pHead2.val > pHead1.val:
                p.next = pHead1
                pHead1 = pHead1.next
            else:
                p.next = pHead2
                pHead2 = pHead2.next
            p = p.next
        return pHead.next

思路
创建一个新链表,遍历两个链表,按大小放入新链表。

17. 树的子结构

题目描述

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSame(self, pRoot1, pRoot2):
        if pRoot1 is None and pRoot2 is not None:
            return False
        if pRoot2 is None:
            return  True
        if pRoot1.val != pRoot2.val:
            return False
        return self.isSame(pRoot1.left, pRoot2.left) and self.isSame(pRoot1.right, pRoot2.right)
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if pRoot1 is None or pRoot2 is None:
            return False
        if self.isSame(pRoot1, pRoot2):
            return True
        return self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)

思路
两个递归函数。一个用来比较树结构是否 一样;一个用来查找子结构的根节点在树中的位置。


18. 二叉树的镜像

题目描述

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def swap(self, root):
        if root is not None:
            tmpNode = root.left
            root.left = root.right
            root.right = tmpNode
            self.swap(root.left)
            self.swap(root.right)
    def Mirror(self, root):
        # write code here
        self.swap(root)
        return root

思路
递归的交换左右子节点。

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.

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        # 0 - right
        # 1 - down
        # 2 - left
        # 3 - up
        rows = len(matrix)
        cols = len(matrix[0])
        direct = 0
        i = j = 0
        result = []
        for _ in range(rows*cols):
            result.append(matrix[i][j])
            matrix[i][j] = None
            if direct == 0:
                if j+1 == cols or matrix[i][j+1] is None:
                    direct = 1
                    i+=1
                else:
                    j+=1
            elif direct == 1:
                if i+1 == rows or matrix[i+1][j] is None:
                    direct = 2
                    j-=1
                else:
                    i+=1
            elif direct == 2:
                if j == 0 or matrix[i][j-1] is None:
                    direct = 3
                    i-=1
                else:
                    j-=1
            elif direct == 3:
                if i == 0 or matrix[i-1][j] is None:
                    direct = 0
                    j+=1
                else:
                    i-=1
        return result

思路
试探边界并改变方向;遍历过的元素标记为None。

20. 包含min函数的栈

题目描述

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

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    def push(self, node):
        # write code here
        self.stack.append(node)
        if not self.min_stack or node < self.min_stack[-1]:
            self.min_stack.append(node)
        else:
            min_item = self.min_stack[-1]
            self.min_stack.append(min_item)
    def pop(self):
        # write code here
        self.min_stack.pop(-1)
        return self.stack.pop(-1)
    def top(self):
        # write code here
        return self.stack[-1]
    def min(self):
        # write code here
        return self.min_stack[-1]

思路
设置一个栈,记录每次压入之后的最小值。


21. 栈的压入、弹出序列

题目描述

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

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        stack = []
        j = 0
        for i in pushV:
            stack.append(i)
            while stack[-1] == popV[j]:
                stack.pop(-1)
                j+=1
                if stack == []:
                    break
        if stack == []:
            return True
        else:
            return False

思路
模拟压入弹出过程,如果栈最终为空,则有效。
这个过程描述为,设置一个栈,遍历压入列表压入,如果栈顶是出栈结点,弹出值。


22. 数组中出现次数超过一半的数字

题目描述

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

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.num_count = {}

    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        for i in numbers:
            if i in self.num_count:
                self.num_count[i] += 1
            else:
                self.num_count[i] = 1
            if self.num_count[i] > len(numbers) // 2:
                return i
        return 0

思路
最直接的算法,创建一个字典,存放数字出现的次数


23. 数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任一一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param numbers int整型一维数组 
# @return int整型
#
class Solution:
    def duplicate(self , numbers ):
        # write code here
        counts = [0] * len(numbers)
        for i in numbers:
            counts[i] +=1
            if counts[i] > 1:
                return i
        return -1

思路
创建一个新数组,存放下标数值本身在数组中出现的次数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值