【剑指Offer】全部题目 —— 通俗易懂的参考答案与解析(Python)

题目1:二维数组中的查找

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

思想: 暴力解决

class Solution:  # array 二维列表
	def Find(self, target, array):  # write code here
		for row in range(len(array)):
			arr = array[row]  # 对于每一行(一维数组),在这个一维数组中查找target。
			for i in range(len(arr)):
				if arr[i] == target:
					return True
		return False
if __name__ == '__main__':
	target = 10
	array = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 12, 15]]
	answer = Solution()
	print(answer.Find(target, array))

题目2:替换空格

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

思想: 库函数

class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
         return s.replace(' ','%20')

题目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
        newlist =[]
        while listNode is not None:
            newlist.append(listNode.val)
            listNode = listNode.next
        return newlist[::-1]

题目4:重建二叉树 ***

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

思想: 二叉树:每个节点最多有两个分支(分支的度小于2)的树结构,可为空树。 前序遍历:根左右+中序遍历:左根右+递归的思想

# -*- 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):
        # write code here
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root = TreeNode(pre[0])
            pos=tin.index(pre[0])#找出根节点在中序遍历的位置
            "递归的思想,根据根节点找出左右子树,还是满足先序遍历和中序遍历,每次的遍历返回的根节点就是二叉树"
            root.left = self.reConstructBinaryTree(pre[1:pos+1], tin[:pos+1])
            root.right = self.reConstructBinaryTree(pre[pos+1:], tin[pos+1:])
        return root

题目5:用两个栈实现队列

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

思想: 栈:先进后出 队:先进先出 push操作:所有元素依次都放在栈1中 pop操作:先将栈1中的元素依次pop到栈2中,pop栈2 的顶点,然后再把栈2中的元素依次pop到栈1中。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        #只在stack1中放元素
        self.stack1.append(node)
    def pop(self):
        if not self.stack1:
            return None
        while self.stack1:
            #把stack1中的元素放到是stack2
            self.stack2.append(self.stack1.pop())
        res = self.stack2.pop()
        #取出后,把stack2中的元素放到是stack1
        while self.stack2:
            self.stack1.append(self.stack2.pop())
        return res

题目6:旋转数组的最小数字

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

思想: 找到满足a[i]>a[i+1]的元素a[i+1]

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if not rotateArray:
            return 0
        for i in range(len(rotateArray)-1):
            if rotateArray[i] > rotateArray[i+1]:
                return rotateArray[i+1]
        return rotateArray[0]

题目7:斐波那契数列

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

思想: 递归

class Solution():
    def Fibnacci(self,n):
        if n <= 0:
            return 0
        if n == 1:
            return 1
        return self.Fibnacci(n-1) + self.Fibnacci(n-2)
# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        if n <= 0:
            return 0
        a = b = 1
        for i in range(2,n):
            a,b=b,a+b
        return b

题目8:跳台阶

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

思想: 青蛙跳台阶仅有两种方式,一阶跳和二阶跳。 我们把情况列出来,假设有n级台阶, 当青蛙一阶跳时,剩余的跳法还剩n-1种; 当青蛙二阶跳时,剩余的跳法还剩n-2种。 由数值特征,我们可以联想到是类似于斐波那契数列的情况:
F(n) = F(n-1) + F(n-2)
n=1, 1种
n=2, 2种
n=3, 3种
n=4, 5种

# -*- coding:utf-8 -*-
# 1,2,3,5,8,11
class Solution:
    def jumpFloor(self, number):
        # write code here
        if number == 1:
            return 1
        elif number == 2:
            return 2
        num1 = 1
        num2 = 2
        for i in range(2, number):
            num1,num2=num2,num1 + num2
        return num2
class Solution():
    def jumpFloor(self,n):
        if n == 1:
            return 1
        if n == 2:
            return 2
        return self.jumpFloor(n-1) + self.jumpFloor(n-2)

题目9:变态跳台阶

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

思想:
原来的青蛙只可以跳上1级或2级,即F(n) = F(n - 1) + F(n - 2)
现在的青蛙可以跳上1到n的任意级,按照之前的解题思路,依然先来看F(n),对于一个n级台阶来说
青蛙第一次可以跳1级,则还剩n - 1级台阶,即F(n - 1)
青蛙第一次可以跳2级,则还剩n - 2级台阶,即F(n - 2)

青蛙第一次可以跳n - 1级,则还剩1级台阶,即F(1)
青蛙第一次可以跳n级,即1种跳法
则F(n) = F(n - 1) + F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1
n=1, 1种
n=2, 2种=1+1
n=3, 4种=2+1+1
n=4, 8种=4+2+1+1
可以得出:在这里插入图片描述

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

题目10:矩形覆盖

我们可以用2X1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2X1的小矩形无重叠地覆盖一个2Xn的大矩形,总共有多少种方法?
比如 n=3 时,2X3 的矩形块有3种覆盖方法:
在这里插入图片描述

思想: 找出规律

class Solution:
    def rectCover(self, number):
        # write code here
        if number == 1:
            return 1
        elif number == 2:
            return 2
        elif number == 0:
            return 0
        num1 = 1
        num2 = 2
        for i in range(2, number):
            num1,num2=num2,num1 + num2
        return num2

题目11:二进制中1的个数

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

思想: 涉及补码反码,自己不了解,以后再补,先附上答案。

class Solution:
# 运行时间:27ms
# 占用内存:5728k
    def NumberOf1(self, n):
        # write code here
        count = 0
        if n < 0:
            n = n & 0xffffffff
        while n!= 0:
            count += 1
            n = (n-1)& n
        return count

题目12:数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0.

**思想:**循环。

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        """
        最简单的方法:base**exponent
        """
        flag = 0
        if base == 0 and exponent<0:
            return False
        if base == 0 and exponent>0:
            return 0
        if exponent == 0:
            return 1
        if exponent < 0:
            flag = 1
        result = 1
        for i in range(abs(exponent)):
            result *= base
        if flag == 1:
            result = 1 / result
        return result

题目13:调整数组顺序使奇数位于偶数前面

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

**思想:**暴力。

class Solution:
    def reOrderArray(self, array):
        res1 = []
        res2 = []
        for i in array:
            if i%2==1:
                res1.append(i)
            else:
                res2.append(i)
        array = res1 + res2
        return array

题目14:链表中倒数第k个结点

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

思想:
1.若链表为空,链表的长度小于k,或者k<0,则返回空
2.两个指针p,q,先让指针p往前走k步,这样就保持p,q指针相差k个数
3.此时p与q一起各往前一步一步走,当p指向空时,q指向倒数第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 k <=0:
            return None
        p = q = head
        t = 0
        while p and t < k:
            p = p.next
            t = t+1
        if t < k:
            return None
        while p != None:
            p = p.next
            q = q.next
        return q

题目15:链表中倒数第k个结点

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

思想:
1.若链表为空,链表的长度小于k,或者k<0,则返回空
2.两个指针p,q,先让指针p往前走k步,这样就保持p,q指针相差k个数
3.此时p与q一起各往前一步一步走,当p指向空时,q指向倒数第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 k <=0:
            return None
        p = q = head
        t = 0
        while p and t < k:
            p = p.next
            t = t+1
        if t < k:
            return None
        while p != None:
            p = p.next
            q = q.next
        return q

题目16:反转链表

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

思想:
思路链接:

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        if not pHead or not pHead.next:
            return pHead
        last = None   #指向上一个节点
        while pHead:
            #先用tmp保存pHead的下一个节点的信息,
            #保证单链表不会因为失去pHead节点的next而就此断裂
            tmp = pHead.next   
            #保存完next,就可以让pHead的next指向last了
            pHead.next = last
            #让last,pHead依次向后移动一个节点,继续下一次的指针反转
            last = pHead
            pHead = tmp
        return last

题目17:合并两个排序的链表

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

思想: 暴力解决
1.先将两个链表转化为数组。合并数组并排序
2.排序好的数组依次加入新的链表

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def Merge(self, pHead1, pHead2):
        if pHead1 is None:
            return pHead2
        if pHead2 is None:
            return pHead1
        num1, num2 = [], []
        while pHead1:
            num1.append(pHead1.val)
            pHead1 = pHead1.next
        while pHead2:
            num2.append(pHead2.val)
            pHead2 = pHead2.next
        ans = num1 + num2
        ans.sort()
        head = ListNode(ans[0])
        pre = head
        for i in range(1, len(ans)):
            node = ListNode(ans[i])
            pre.next = node
            pre = pre.next
        return head

题目18:树的子结构

输入两棵二叉树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 HasSubtree(self, pRoot1, pRoot2):
        # write code here
        if not pRoot1 or not pRoot2:
            return False
            #从根节点,左节点,右节点比较
        return self.is_subtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
     
    def is_subtree(self, A, B):
        #B为空,说明在A中找到了B
        if not B:
            return True
        if not A or A.val != B.val:
            return False
        return self.is_subtree(A.left,B.left) and self.is_subtree(A.right, B.right)

题目19:二叉树的镜像

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

思想: 递归,从上到下一直更换左右根节点

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

题目20:顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.

思想: 可以模拟魔方逆时针旋转的方法,一直做取出第一行的操作。
在turn中,for循环(行列互换)将矩阵[[5,6,7,8],[9,10,11,12],[13,14,15,16]]变成矩阵[[5,9,13],[6,10,14],[7,11,15],[8,12,16]],在进行reversr操作变为,[[8,12,16],[7,11,15],[6,10,14],[5,9,13]],第一行即为要输出的元素。

class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        result = []
        while(matrix):
            result+=matrix.pop(0)#抛出第一行
            if not matrix or not matrix[0]:
                break
            matrix = self.turn(matrix)
        return result
        #旋转矩阵使得第一行为所需元素
    def turn(self,matrix):
        num_r = len(matrix)
        num_c = len(matrix[0])
        newmat = []
        for i in range(num_c):
            newmat2 = []
            for j in range(num_r):
                newmat2.append(matrix[j][i])
            newmat.append(newmat2)
        newmat.reverse()#行颠倒交换
        return newmat

题目21:包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

思想:

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)
    def pop(self):
        # write code here
        #当pop最小元素时,两个都要pop,不是最小元素时,只需stack.pop即可。
        if self.stack[-1] == self.min_stack[-1]:
            self.min_stack.pop()
        self.stack.pop()
    def top(self):
        # write code here
        return self.stack[-1]
    def min(self):
        # write code here
        return self.min_stack[-1]

题目22:栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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 = []
        for i in pushV:
            stack.append(i)#每输入一个,判断是不是跟出栈序列的第一个相同
            while stack and stack[-1] == popV[0]:
                stack.pop()#stack的末尾
                popV.pop(0)#popV的开头
        return True if not stack else False

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

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

思想: 递归

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        l=[]
        if not root:
            return []
        q=[root]
        while len(q):
            t=q.pop(0)
            l.append(t.val)#l存储打印的序列
            if t.left:
                q.append(t.left)
            if t.right:
                q.append(t.right)
        return l  

题目24:二叉搜索树的后序遍历序列

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

思想: 递归
后序遍历:左右根。
二叉搜索树定义:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
把数组分成三部分,比如[4,8,6,12,16,14,10],10就是根节点,4,8,6都是左子树,12,16,14,10都是右子树,然后针对左右子树再去判断是不是符合根节点、左右子树这一个规律(左子树都比根节点小,右子树都比根节点大)

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self,sequence):
        # write code here
        if len(sequence)==0:
            return False
        index = 0
        for i in range(len(sequence)):
            if sequence[i]>sequence[-1]:
                index = i
                break
        for j in range(i,len(sequence)):
            if sequence[j]<sequence[-1]:
                return False
        left = True
        right = True
        if len(sequence[:index])>0:
            left = self.VerifySquenceOfBST(sequence[:index])
        if len(sequence[index:-1])>0:
            right = self.VerifySquenceOfBST(sequence[index:-1])
        return left and right

题目25:二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

思想: 不是特别懂题意
在题目要求中,要注意两点,第一是从根节点开始到叶子结点结束,第二是所有路径。
所以,我们可以利用递归,用带记忆的深度遍历法来进行。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# -*- coding:utf-8 -*-
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return []
        if root and not root.left and not root.right and root.val == expectNumber:
            return [[root.val]]
        res = []
        left = self.FindPath(root.left, expectNumber-root.val)
        right = self.FindPath(root.right, expectNumber-root.val)
        for i in left+right:
            res.append([root.val]+i)
        return res

题目26:复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

思想:
深拷贝
深度拷贝, 链表1 和 链表2 完全拷贝了父对象及其子对象,两者是完全独立的。

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
import copy
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        chead=copy.deepcopy(pHead)
        return chead
        # write code here

题目27:二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

思想:
1.将左子树构造成双链表,并返回链表头节点。
2.定位至左子树双链表最后一个节点。
3.如果左子树链表不为空的话,将当前root追加到左子树链表。
4.将右子树构造成双链表,并返回链表头节点。
5.如果右子树链表不为空的话,将该链表追加到root节点之后。
6.根据左子树链表是否为空确定返回的节点。
在这里插入图片描述

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Convert(self, pRootOfTree):
        root=pRootOfTree
        if not root:
            return None
        if not root.left and not root.right:
            return root
        # 将左子树构建成双链表,返回链表头
        left = self.Convert(root.left)
        p = left
        # 定位至左子树的最右的一个结点
        while left and p.right:
            p = p.right
        # 如果左子树不为空,将当前root加到左子树链表
        if left:
            p.right = root
            root.left = p
        # 将右子树构造成双链表,返回链表头
        right = self.Convert(root.right)
        # 如果右子树不为空,将该链表追加到root结点之后
        if right:
            right.left = root
            root.right = right             
        return left if left else root

自己分析的备注:self.Convert(6)–>self.Convert(4)这时left=4,再往下执行 4与6互相指向–> self.Convert(8) 这时左子树遍历完毕,返回left表示左子树的头结点–>再找左子树最右的叶节点p,与root链接–>self.Convert(14)–>self.Convert(12) left=12,12与14互相指向,–>self.Convert(16)这时右子树遍历完毕,right表示头结点12,在与root链接。

题目28:字符串的排列

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

思想: 暴力解决

import itertools
class Solution:
    def Permutation(self, ss):
        # write code here
        if not ss:
            return []
            #permutations求数列的组合
        return sorted(list(set(map(''.join, itertools.permutations(ss)))))

题目29:数组中出现次数超过一半的数字

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

思想:
1.先找到重复的数字,如果有数字出现的次数超过数组长度一半,则中间位置肯定是重复的数字。
2.判断等于中间位置的数有多少个,是否满足要求。

class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        count = 0
        numbers.sort()
        res = numbers[len(numbers)//2]#一定是重复的数字
        for i in numbers:
            if i == res:
                count +=1
        if count >len(numbers)/2:
            return res
        else:
            return 0

题目30:最小的K个数

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

思想:
如果输入的n不存在则输出[]空list,如果K大于输入的长度也是同样输出为空的
对输入的数据进行排序,去0:k的数即为所取得的最小的k个数

class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        n = len(tinput)
        if n == 0 or k > n or k==0:
            return []
        else:
            return sorted(tinput)[:k]

题目31:连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

思想:
最大和连续子数组一定有如下几个特点:
1、第一个不为负数
2、如果前面数的累加值加上当前数后的值会比当前数小,说明累计值对整体和是有害的;如果前面数的累加值加上当前数后的值比当前数大或者等于,则说明累计值对整体和是有益的。
步骤:
1、定义两个变量,一个用来存储之前的累加值,一个用来存储当前的最大和。遍历数组中的每个元素,假设遍历到第i个数时:
①如果前面的累加值为负数或者等于0,那对累加值清0重新累加,把当前的第i个数的值赋给累加值。
②如果前面的累加值为整数,那么继续累加,即之前的累加值加上当前第i个数的值作为新的累加值。
2、判断累加值是否大于最大值:如果大于最大值,则最大和更新;否则,继续保留之前的最大和

class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        #先判断所有的数是否全小于0
        b=max(array)
        if max(array)<=0:
            return b
        if b>0:
            maxsofar = 0
            #循环计算相差i-j个数的和,x[i:j]之和 = x[i:j-1]之和 + x[j]
            for i in range(0,len(array)):
                presum = 0
                for j in range(i,len(array)):
                    presum += array[j]
                    maxsofar = max(maxsofar, presum)
            return maxsofar
 #好理解的实现
 def function(lists):
    max_sum = lists[0]
    pre_sum = 0
    for i in lists:
        if pre_sum < 0:
            pre_sum = i
        else:
            pre_sum += i
        if pre_sum > max_sum:
            max_sum =  pre_sum
    return max_sum
 
def main():
    lists=[6,-3,1,-2,7,-15,1,2,2]
    print function(lists)
    
if __name__ == "__main__":
    main()

题目32:整数中1出现的次数(从1到n整数中1出现的次数)

求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思想:

class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        ans = 0
        #遍历1-n所有数字,将数字转换为字符数组。统计字符数组中1的个数。得到答案。
        for i in range(1,n+1):
            s = str(i)
            for c in s:
                if c == '1':
                    ans += 1
        return ans

题目33:把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

思想:

import itertools
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        if not numbers:
            return ''
        #得到字符列表的所有可能的排列
        l = list(itertools.permutations(str(i) for i in numbers))
        res = []
        for i in l:
            j = int(''.join(i))
            res.append(j)#合并每个排列
        res.sort()#排序后选择最小的
        return res[0]

题目34:丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

思想:
因为丑数是由 2 x ∗ 3 y ∗ 5 z 2^x*3^y*5^z 2x3y5z
下一个丑数肯定是由此丑数前面的三个丑数乘上2、3、5最小的那个

class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index == 0:
            return 0
        if index == 1:
            return 1
        x, y, z = 0, 0, 0
        ans = [1]
        for i in range(1, index):
            #因为丑数是由2^x*3^y*5^z
            #下一个丑数肯定是由此丑数前面的三个丑数乘上2、3、5最小的那个
            ans.append(min(ans[x]*2, ans[y]*3, ans[z]*5))
            if ans[i] == ans[x]*2:
                x+= 1
            if ans[i] == ans[y]*3:
                y+= 1
            if ans[i] == ans[z]*5:
                z+= 1
        return ans[index - 1]

题目35:第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

思想:

class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if not s:
            return -1
        for i,ch in enumerate(s):
            if s.count(ch)==1:
                return i

题目36:循环数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思想1:
1.排序后的元素在data的什么位置,代表了前面有几个比他大的,也就是说有几个逆序对

牛客只通过50%

class Solution:
    def InversePairs(self, data):
        # write code here
        sortData = sorted(data)
        count = 0
        for i in sortData:
            pos = data.index(i)
            count += pos
            data.pop(pos)
        return count

思想2:
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
在这里插入图片描述

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        count, result = self.merge_sort(data)
        return count%1000000007

    def merge_sort(self, a_list):
        n = len(a_list)
        count = 0
        if n <= 1:
            return count, a_list
        # 拆分
        count_l, left = self.merge_sort(a_list[:n // 2])
        count_r, right = self.merge_sort(a_list[n // 2:])
        # 合并排序
        count_merge, merge = self.merge(left, right)
        count = count_l + count_r + count_merge
        return count, merge

    def merge(self, left, right):
        count = 0
        l = r = 0
        result = []
        while l < len(left) and r < len(right):
            if left[l] <= right[r]:
                result.append(left[l])
                l += 1
            else:
                result.append(right[r])
                r += 1
                # 当右边的元素被插入时,证明这个元素比左边的剩下的所有元素都小
                # 可以组成len(left)-l个逆序对
                count += len(left) - l
        result += left[l:] + right[r:]        
        return count, result

merge([7],[5]):(1, [5, 7])
merge([5,7],[4,6]): (3, [4, 5, 6, 7])
5与4比较,result.append(right[0]) result=[4],r=1,count=2-0=2因为左边的都大于4
5与6比较,正常 result=[4,5] , l l l=1
7与6比较,逆序,count=2+2-1=3,r=2, result=[3,5]+[6]+left[1]+right[2]=[3,5]+[6]+[7]

题目37:两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

思想:
先将一个链表转化为数组,再看另一个链表的数据有没有数组内出现

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, head1, head2):
        # write code here
        list1 = []
        node1 = head1
        node2 = head2
        #将链表转为列表
        while node1:
            list1.append(node1.val)
            node1 = node1.next
        #判断链表中的元素是否在列表1 出现
        while node2:
            if node2.val in list1:
                return node2
            else:
                node2 = node2.next

题目38:数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

思想:

class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        return data.count(k)

题目39:二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思想: 递归

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        Depth=0
        if not pRoot:
            return Depth
        return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

题目40:平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

思想: 递归

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if pRoot == None:
            return True
            #该根节点的左右子树是否满足相差小于1
        if abs(self.TreeDepth(pRoot.left)-self.TreeDepth(pRoot.right)) > 1:
            return False
            #再看左右子树是不是平衡二叉树
        return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right) 
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot == None:
            return 0
        nLeft = self.TreeDepth(pRoot.left)
        nRight = self.TreeDepth(pRoot.right)
        return max(nLeft+1,nRight+1)#(nLeft+1 if nLeft > nRight else nRight +1)

题目41:数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

思想:

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

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

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
Good Luck! 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。

思想:
使用滑动窗口的方法来解决,不断往前移动窗口
设定一个动态的窗口,p_low指向窗口头部,
p_high指向窗口尾部,窗口之间的值,为目标值。
如果目标值为tsum,那就是其中一个解。否则移动窗口。

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        #错误判断处理,如果小于3的话 无解
        if tsum < 3:
            return []
        #设定初始的滑动窗口大小
        p_low = 1
        p_high = 2

        ans = []
        while p_low < p_high:
            #计算滑动窗口现在圈中的大小
            cur_sum = sum(range(p_low,p_high+1))
            if cur_sum == tsum:
                #找到一组解,并记录到ans数组中。
                ans.append(range(p_low,p_high+1))
                #移动滑动窗口,并寻找下一组解。
                p_high = p_high + 1
            elif cur_sum < tsum:
                p_high = p_high + 1
            else :
                p_low = p_low + 1
        return ans

题目43:和为S的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。对应每个测试案例,输出两个数,小的先输出。

思想:
从左右一起查找
因为当两个数的和一定的时候, 两个数字的间隔越大, 乘积越小
所以直接输出查找到的第一对数即可

class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        if not array or not tsum:
            return []
        head = 0
        tail = len(array)-1
        while head < tail:
            cur_sum = array[head]+array[tail]
            if tsum == cur_sum:
                return [array[head],array[tail]]
            elif cur_sum <tsum:
                head = head + 1
            else:
                tail = tail -1
        return []

题目44:左旋转字符串

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

思想: 不懂,先贴上代码,欢迎大家评论

class Solution:
    def LeftRotateString(self, s, n):
        if s:
            #注意n大于数组长度时也可左移
            n = n % len(s)
            return s[n:] + s[:n]
        else:
            return ''

题目45:翻转单词顺序列

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?!

思想:
注意是句子语序反了,单词可是正确的哦
先转化为列表,利用索引反序即可

class Solution:
    def ReverseSentence(self, s):
        # write code here
        l=s.split(' ') #l为列表
        # ['student.', 'a', 'am', 'I']
        return ' '.join(l[::-1])

题目46:扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

思想:
1.数组的长度应该有5个0-13的数字,若为空,返回0
2.先将数组排序,计算0元素的个数
3.a数组是抛去0之外的且排序好的列表
4.计算a中有无重复元素,有返回0
5.计算a中相邻元素的间隔总数与0元素个数的关系

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        """
        思路如下:
        1.数组的长度应该有5个0-13的数字,若为空,返回0
        2.先将数组排序,计算0元素的个数
        3.a数组是抛去0之外的且排序好的列表
        4.计算a中有无重复元素,有返回0
        5.计算a中非0元素的(排序后)的差-1的总和与0个数的关系
        """
        if not numbers:return False
        numbers.sort()
        zeros=numbers.count(0)
        a=numbers[zeros:]
        for x in a:
            if a.count(x)>1:
                return False
        small = 0
        aa=[ a[i]-a[i-1]-1 for i in range(1,len(a))]
        gap=sum(aa)
        if gap<=zeros:
            return True
        else:
            return False       

题目47:孩子们的游戏(圆圈中最后剩下的数)

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
如果没有小朋友,请返回-1

思想:

class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if not m or not n:
            return -1
        res = range(n)
        i = 0
        while len(res)>1:
            #i作为初始点,再喊m-1个
            i = (i+m-1)%len(res)
            res.pop(i)
        return res[0]

题目48:求1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思想: 递归

class Solution:
    def Sum_Solution(self, n):
        if n==1:
            return 1
        return self.Sum_Solution(n-1)+n

题目49:不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

思想:

# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        s=[num1,num2]
        return sum(s)

题目50:把字符串转换成整数

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:输入一个字符串,包括数字字母符号,可以为空。
输出描述:如果是合法的数值表达则返回该数字,否则返回0。

思想:

class Solution:
    def StrToInt(self, s):
        # write code here
        try:
            a=int(s)#如果不全是数字的话会抛出异常,或者12-3也不行
            return a
        except:
            return 0

题目51:数组中重复的数字

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

思想:

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        #注意哦:题目中找的是第一个重复的数字
        l=list(set(numbers))
        for i in l:
            if numbers.count(i)!=1:
                yyyyyy

题目52:构建乘积数组

给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)

思想: 循环

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        B = [1] * len(A)
        for i in range(0, len(A)):
            for j in range(0, len(B)):
                if i != j:
                    B[i] *= A[j]
        return B

题目53:正则表达式匹配

请实现一个函数用来匹配包括’ . . .‘和’ ∗ * ‘的正则表达式。模式中的字符’ . . .‘表示任意一个字符,而’ ∗ * '表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

思想:
1.s为空,pattern为空
2.s为不空,pattern为空
3.s为空,pattern不为空:讨论pattern的第二个字符是否为*
4.s不为空,pattern不为空,讨论pattern的第二个字符是否为*,

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # 如果s与pattern都为空,则True
        if len(s) == 0 and len(pattern) == 0:
            return True
        # 如果s不为空,而pattern为空,则False
        elif len(s) != 0 and len(pattern) == 0:
            return False
        # 如果s为空,而pattern不为空,则需要判断
        elif len(s) == 0 and len(pattern) != 0:
            # pattern中的第二个字符为*,则pattern后移两位继续比较
            if len(pattern) > 1 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
        # s与pattern都不为空的情况
        else:
            # pattern的第二个字符为*的情况
            if len(pattern) > 1 and pattern[1] == '*':
                # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空
                if s[0] != pattern[0] and pattern[0] != '.':
                    return self.match(s, pattern[2:])
                else:
                    # 如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况
                    # pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的
                    # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配
                    # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位
                    return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
            # pattern第二个字符不为*的情况
            else:
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    return False

题目54:表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

思想:

class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        try :
            p = float(s)
            return True
        except:
            return False

题目55:字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:如果当前字符流没有存在出现一次的字符,返回#字符。

思想:
字典 键表示字母,键值表示出现的次数,
在插入字母时,键不存在,创建键,并绑定键对应的值; 键存在,修改键绑定的值

class Solution:
    # 返回对应char
    def __init__(self):
        self.s=''
        self.dict1={}
    def FirstAppearingOnce(self):
        # write code here
        for i in self.s:
            if self.dict1[i]==1:
                return i
        return '#'
    def Insert(self, char):
        # write code here
        self.s=self.s+char
        if char in self.dict1:
            """
            字典[键] = 表达式
            """
            self.dict1[char]=self.dict1[char]+1
        else:
            self.dict1[char]=1

题目56:链表中环的入口结点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思想:
将listnode节点(值和指针)依次放进列表的同时,判断节点是否以前在列表出现过,若出现则是入口节点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        linkls = []
        while pHead:
            if pHead in linkls:
                return pHead
            linkls.append(pHead)
            pHead = pHead.next
        return None

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

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

思想:
将listnode节点(值和指针)依次放进列表的同时,判断节点是否以前在列表出现过,若出现则是入口节点

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

class Solution:
    def deleteDuplication(self, pHead):
        res = []
        while pHead:
            res.append(pHead.val)
            pHead = pHead.next
            """
            filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
            该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,
            然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
            """
        res = list(filter(lambda c: res.count(c) == 1, res))
        """
        这部分代码没有头结点,即第一个节点的指针指向第一个带有数据的点,头结点的数据域可以放任意值
        head = ListNode(res[0])
        pre = head
        for i in range(1, len(res)):
            node = ListNode(res[i])
            pre.next = node
            pre = pre.next
        return head
        """
        dummy = ListNode(len(res))#头结点的数据域放的链表的长度
        pre = dummy
        for i in res:
            node = ListNode(i)
            pre.next = node
            pre = pre.next
        return dummy.next

题目58:二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思想:
中序:DBHEIAFCG
若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )
若该节点不存在右子树:这时分两种情况:

  • 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D )

  • 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点)。
    在这里插入图片描述

# -*- 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):
        # write code here
        if pNode.right:#有右子树
            p=pNode.right
            while p.left:
                p=p.left
            return p
        while pNode.next:#无右子树,则找第一个当前节点是父节点左孩子的节点
            if(pNode.next.left==pNode):
                return pNode.next
            pNode = pNode.next#沿着父节点向上遍历
        return  #到了根节点仍没找到,则返回空

题目59:对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

思想: 递归
先判断根节点,再判断左子树与右子树是否相同

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

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

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思想:
题目23的加强版
23题是从上往下打印出二叉树的每个节点,同层节点从左至右打印。要求的输出样式是:[1, 2, 3, 4, 5, 6, 7]。
而这道题所不同的地方是:其要求输出的样式是:[[1], [3,2], [4,5,6,7]]。和上段中的题目相比,这道题不仅要求按序输出节点值,还要求包含以下信息:

  1. 每一层所包含的树节点;
  2. 偶数层的树节点需倒序。
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        res=[]#返回最终结果
        if not pRoot:
            return res
        q=[pRoot]
        flag=True#标记是否是偶数
        while q:
            qv=[] #当前节点的值
            nq=[] #当前节点的左右子树的根节点
            flag=not flag
            for node in q:
                qv.append(node.val)
                if node.left:
                    nq.append(node.left)
                if node.right:
                    nq.append(node.right)
            q=nq #更新下一次迭代的根节点序列
            res.append(qv[::-1])  if flag else  res.append(qv)
        return res  

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

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

思想:
只需要将上一题的flag去掉即可

# -*- 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):
        res=[]#返回最终结果
        if not pRoot:
            return res
        q=[pRoot]
        while q:
            qv=[] #当前节点的值
            nq=[] #当前节点的左右子树的根节点
            for node in q:
                qv.append(node.val)
                if node.left:
                    nq.append(node.left)
                if node.right:
                    nq.append(node.right)
            q=nq #更新下一次迭代的根节点序列
            res.append(qv)  

题目62:序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树

思想:
序列化:递归
反序列化:递归

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.flag = -1
    #递归方式序列化
    def Serialize(self, root):
        # write code here
        if not root:
            return '#,'
        return str(root.val)+','+self.Serialize(root.left)+self.Serialize(root.right)
         
    def Deserialize(self, s):
        # write code here
        self.index += 1
        l = s.split(',')
         
        if self.index >= len(s):
            return None
        root = None
        if l[self.index] != '#':
            root = TreeNode(int(l[self.index]))
            root.left = self.Deserialize(s)
            root.right = self.Deserialize(s)
        return root

题目63:二叉搜索树的第k个结点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

思想:
二叉搜索树的中序遍历正好是一个递增的序列, 因此中序遍历的第K个结点就是二叉搜索树的第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):
        # write code here
        global result
        result=[]
        self.midnode(pRoot)
        if  k<=0 or len(result)<k:
            return None
        else:
            return result[k-1]              
    def midnode(self,root):#中序遍历
        if not root:
            return None
        self.midnode(root.left)
        result.append(root)
        self.midnode(root.right)

题目64:数据流中的中位数

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

思想:

# -*- coding:utf-8 -*-
class Solution:
    data=[]
    def Insert(self, num):
        # write code here
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,x):
        # write code here
        l=len(self.data)
        if l%2==1:
            return self.data[l/2]
        else:
            return (self.data[l/2]+self.data[l/2-1])/2.0

题目65:滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};
针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1},
{2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1},
{2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

思想:

class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if size <= 0:
            return []
        res = []
        for i in range(0, len(num)-size+1):
            res.append(max(num[i:i+size]))
        return res

题目66:矩阵中的路径在这里插入图片描述

思想:

class Solution:
    """ 在矩阵中寻找是否存在路径等于给定的字符串
    Returns:
        matrix -- 寻找路径的字符矩阵
        rows   -- 矩阵的行数
        cols   -- 矩阵的列数
        path   -- 待寻找的路径
    """
    def hasPath(self, matrix, rows, cols, path):
        # 为了保证当前路径上已经被访问过的结点不再重复访问
        # 设置 vis 来标记某个元素是否被访问过,容量和 matrix 相同
        vis = [True] * rows * cols
        for i in range(rows):
            for j in range(cols):
                # 从 matrix[i][j] 开始寻找是否存在路径
                if self.hasPathAtAStartPoint(matrix, rows, cols, i, j, path, vis):
                    # 如果存在则返回True
                    return True
        # 如果从所有位置出发都不能找到,则返回False
        return False

    # 从某个点(x, y)出发寻找路径
    def hasPathAtAStartPoint(self, matrix, rows, cols, i, j, path, vis):
        # index 表示当前访问元素的位置
        index = i * cols + j
        # 递归的终止条件
        # 如果路径存在则返回True
        if not path:
            return True
        # 如果访问越出边界、当前位置元素不是path的起始元素或者当前位置已被访问过,直接返回False
        if i < 0 or i >= rows or j < 0 or j >= cols or matrix[index]!=path[0] or vis[index]==False:
            return False
        # 执行这一步,说明上面的if都不满足,说明找到了一下个点
        # 关键步骤
        vis[index] = False
        # 递归条件,如果以(0, 0)作为原点
        # 向上走: i - 1
        # 向下走: i + 1
        # 向前走: j + 1
        # 向后走: j _ 1
        if(self.hasPathAtAStartPoint(matrix,rows,cols,i+1,j,path[1:],vis) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i-1,j,path[1:],vis) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j-1,path[1:],vis) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j+1,path[1:],vis)):
            return True
        #执行这一步,说明上面的if都不满足,则没有找到下一个,即当中的四个点的标签还是true关键步骤
        vis[index] = True
        return False	

题目67:机器人的运动范围

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

思想:

# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        if rows < 1 or cols < 1 or threshold < 0:
            return 0
        visited = [False] * (rows * cols)
        return self.moving(threshold, rows, cols, 0, 0, visited)

    def moving(self, threshold, rows, cols, curx, cury, visited):
        cnt = 0
        if 0 <= curx < cols and 0 <= cury < rows and not visited[cury * cols + curx]:
            if self.calbitsum(curx) + self.calbitsum(cury) <= threshold:
                visited[cury * cols + curx] = True
                # 能到达格子数为当前位置+四个方向能走到的格子数总和
                #走到这,说明这次的调用满足条件,所以加1
                cnt = 1 + self.moving(threshold, rows, cols, curx - 1, cury, visited) \
                      + self.moving(threshold, rows, cols, curx, cury - 1, visited) \
                      + self.moving(threshold, rows, cols, curx + 1, cury, visited) \
                      + self.moving(threshold, rows, cols, curx, cury + 1, visited)
        return cnt
    #求解每个数的数位和
    def calbitsum(self, x):
        ressum = 0
        while x != 0:
            ressum += x % 10
            x /= 10
        return ressum

题目68:剪绳子

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入描述:输入一个数n,意义见题面。(2 <= n <= 60)
输出描述:输出答案。

思想: 动态规划
在长度为n的绳子所求为f(n),剪下一刀后剩下的两段长度是i和n-i,在这个上面还可能继续减(子问题),所以:f(n)=f(i)+f(n-i) i=[1,n//2]

# -*- coding:utf-8 -*-
class Solution:
    def cutRope(self,number):
        if number == 0:
            return 0
        if number == 1:
            return 1
        if number == 2:
            return 2
        if number == 3:
            return 3
        if number == 4:
            return 4
        result = [0,1,2,3]
        for i in range(4,number+1):
            max = 0
            for j in range(1,i//2+1):
                temp = result[j] * result[i-j]
                if temp > max:
                    max = temp
            result.append(max)
        return result[number]
# 输出结果为18


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值