当前位置:   article > 正文

牛客网剑指offer(Python版)_剑指offer官网

剑指offer官网

剑指offer官网:  https://www.nowcoder.com/ta/coding-interviews

写在前面的话

刷剑指offer的时候只需要提交函数核心部分,但是在公司实际笔试时却需要自己写好输入输出,各个题目的输入也都是五花八门的,在这里记录一下一般常用的输入的写法,以免忘记。

1.输入一维数组

  1. #输入一维数组的方法:
  2. # 方法1
  3. num = [int(n) for n in input().split()]
  4. print(num)
  5. # 方法二
  6. num = list(map(int, input().strip().split()))
  7. print(num)

这两种输入方法的结果是一样的:

 

 2.输入二维数组

  1. #输入指定大小的数组
  2. M = int(input()) # 行
  3. N = int(input()) # 列
  4. A = [[0]*N] * M # 初始化二维矩阵
  5. for i in range(M): # 从键盘输入矩阵
  6. A[i] = input().split(" ")
  7. A[i] = [int(j) for j in A[i]]
  8. '''
  9. 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
  10. for j in range(N):
  11. A[i][j]=int(A[i][j])
  12. '''
  13. print(A)

  1. #输入指定行不定列的数组
  2. M = int(input()) # 行
  3. A = [[0]] * M # 初始化二维矩阵
  4. for i in range(M): # 从键盘输入矩阵
  5. A[i] = input().split(" ")
  6. A[i] = [int(j) for j in A[i]]
  7. '''
  8. 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
  9. for j in range(N):
  10. A[i][j]=int(A[i][j])
  11. '''
  12. print(A)

 

-------------------------------------------------------------------------------------------------------------------------------------- 

链表

3、从头到尾打印链表

提交代码1:

最简单是思路是用递归,依次滑动链表指针,让最前的元素保持在最后。

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. # 返回从尾部到头部的列表值序列,例如[1,2,3]
  8. def printListFromTailToHead(self, listNode):
  9. # write code here
  10. if listNode is None:
  11. return []
  12. return self.printListFromTailToHead(listNode.next) + [listNode.val]

提交代码2:

  • 用一个list把链表中的元素依次压入,然后对链表进行翻转。
  • 注意:python中list.reverse()没有返回值,故不能直接return list.reverse();也不能令list2=list.reverse()再return list2.
  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. # 返回从尾部到头部的列表值序列,例如[1,2,3]
  8. def printListFromTailToHead(self, listNode):
  9. if not listNode:
  10. return []
  11. result=[]
  12. while listNode:
  13. result.append(listNode.val)
  14. listNode=listNode.next
  15. result.reverse()
  16. return result

 提交代码3:

  • 考虑栈的特性:先进后出。
  1. # -*- coding:utf-8 -*-
  2. # 运行时间:33ms
  3. # 占用内存:5852k
  4. # class ListNode:
  5. # def __init__(self, x):
  6. # self.val = x
  7. # self.next = None
  8. class Solution:
  9. # 返回从尾部到头部的列表值序列,例如[1,2,3]
  10. def printListFromTailToHead(self, listNode):
  11. if not listNode:
  12. return []
  13. res=[]
  14. result=[]
  15. while listNode:
  16. res.append(listNode.val)
  17. listNode=listNode.next
  18. while res:
  19. result.append(res.pop())
  20. return result

 提交代码4:

从头到尾遍历链表,将值存在列表res中,最后将res逆序输出。

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. # 返回从尾部到头部的列表值序列,例如[1,2,3]
  8. def printListFromTailToHead(self, listNode):
  9. # write code here
  10. res = []
  11. p = listNode
  12. while p:
  13. res.append(p.val)
  14. p = p.next
  15. return res[::-1]

14、链表中倒数第k个节点

 题解1:

  1. class Solution:
  2. def FindKthToTail(self, head, k):
  3. # write code here
  4. if head==None or k<=0:
  5. return None
  6. #设置两个指针,p2指针先走(k-1)步,然后再一起走,当p2为最后一个时,p1就为倒数第k个 数
  7. p2=head
  8. p1=head
  9. #p2先走,走k-1步,如果k大于链表长度则返回 空,否则的话继续走
  10. while k>1:
  11. if p2.next!=None:
  12. p2=p2.next
  13. k-=1
  14. else:
  15. return None
  16. #两个指针一起 走,一直到p2为最后一个,p1即为所求
  17. while p2.next!=None:
  18. p1=p1.next
  19. p2=p2.next
  20. return p1

题解2:

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def FindKthToTail(self, head, k):
  8. # write code here
  9. l=[]
  10. while head!=None:
  11. l.append(head)
  12. head=head.next
  13. if k>len(l) or k<1:
  14. return None
  15. return l[-k]

 15、反转链表

思路:1->2->3->4->5,遍历链表,把1的next置为None,2的next置为1,以此类推,5的next置为4。得到反转链表。需要考虑链表只有1个元素的情况。图中有具体的每步迭代的思路,最后输出pre而不是cur是因为最后一次迭代后cur已经指向None了,而pre是完整的反向链表。 

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. # 返回ListNode
  8. def ReverseList(self, pHead):
  9. # write code here
  10. if pHead==None or pHead.next==None:
  11. return pHead
  12. pre = None
  13. cur = pHead
  14. while cur!=None:
  15. tmp = cur.next
  16. cur.next = pre
  17. pre = cur
  18. cur = tmp
  19. return pre

注:此题的进阶是Leetcode第25题:k个一组翻转链表 

思路一:栈 

 

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  8. dummy = ListNode(0)
  9. p = dummy
  10. while True:
  11. count = k
  12. stack = []
  13. tmp = head
  14. while count and tmp:
  15. stack.append(tmp)
  16. tmp = tmp.next
  17. count -= 1
  18. # 注意,目前tmp所在k+1位置
  19. # 说明剩下的链表不够k个,跳出循环
  20. if count :
  21. p.next = head
  22. break
  23. # 翻转操作
  24. while stack:
  25. p.next = stack.pop()
  26. p = p.next
  27. #与剩下链表连接起来
  28. p.next = tmp
  29. head = tmp
  30. return dummy.next

思路二:递归

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
  8. cur = head
  9. count = 0
  10. while cur and count!= k:
  11. cur = cur.next
  12. count += 1
  13. if count == k:
  14. cur = self.reverseKGroup(cur, k)
  15. while count:
  16. tmp = head.next
  17. head.next = cur
  18. cur = head
  19. head = tmp
  20. count -= 1
  21. head = cur
  22. return head

 16、合并两个排序列表

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. # 返回合并后列表
  8. def Merge(self, pHead1, pHead2):
  9. # write code here
  10. res = head = ListNode(0)
  11. while pHead1 and pHead2:
  12. if pHead1.val < pHead2.val:
  13. head.next = pHead1
  14. pHead1 = pHead1.next
  15. elif pHead1.val >= pHead2.val:
  16. head.next = pHead2
  17. pHead2 = pHead2.next
  18. head = head.next
  19. head.next = pHead1 or pHead2
  20. return res.next

25、复杂链表的复制

递归: 

  1. # -*- coding:utf-8 -*-
  2. # class RandomListNode:
  3. # def __init__(self, x):
  4. # self.label = x
  5. # self.next = None
  6. # self.random = None
  7. class Solution:
  8. # 返回 RandomListNode
  9. def Clone(self, pHead):
  10. # write code here
  11. if not pHead: return
  12. newNode = RandomListNode(pHead.label)
  13. newNode.random = pHead.random
  14. newNode.next = self.Clone(pHead.next)
  15. return newNode

哈希表法:

  1. class Solution:
  2. def Clone(self, head):
  3. nodeList = [] #存放各个节点
  4. randomList = [] #存放各个节点指向的random节点。没有则为None
  5. labelList = [] #存放各个节点的值
  6. while head:
  7. randomList.append(head.random)
  8. nodeList.append(head)
  9. labelList.append(head.label)
  10. head = head.next
  11. #random节点的索引,如果没有则为1
  12. labelIndexList = map(lambda c: nodeList.index(c) if c else -1, randomList)
  13. dummy = RandomListNode(0)
  14. pre = dummy
  15. #节点列表,只要把这些节点的random设置好,顺序串起来就ok了。
  16. nodeList=map(lambda c:RandomListNode(c),labelList)
  17. #把每个节点的random绑定好,根据对应的index来绑定
  18. for i in range(len(nodeList)):
  19. if labelIndexList[i]!=-1:
  20. nodeList[i].random=nodeList[labelIndexList[i]]
  21. for i in nodeList:
  22. pre.next=i
  23. pre=pre.next
  24. return dummy.next

 36、两个链表的第一个公共结点

假定 List1长度: a+n  List2 长度:b+n, 且 a<b

那么 p1 会先到链表尾部, 这时p2 走到 a+n位置,将p1换成List2头部

接着p2 再走b+n-(n+a) =b-a 步到链表尾部,这时p1也走到List2的b-a位置,还差a步就到可能的第一个公共节点。

将p2 换成 List1头部,p2走a步也到可能的第一个公共节点。如果恰好p1==p2,那么p1就是第一个公共节点。  或者p1和p2一起走n步到达列表尾部,二者没有公共节点,退出循环。 同理a>=b.

时间复杂度O(n+a+b)

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def FindFirstCommonNode(self, pHead1, pHead2):
  8. # write code here
  9. p1 = pHead1
  10. p2 = pHead2
  11. while p1 != p2:
  12. p1 = p1.next if p1 != None else pHead2
  13. p2 = p2.next if p2 != None else pHead1
  14. return p1

55、链表中环的入口地点

法1:遍历这个链表,把链表每个元素记录在list里,然后一旦遇到了重复节点则存在环,不然就不存在

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def EntryNodeOfLoop(self, pHead):
  8. # write code here
  9. temp = []
  10. p = pHead
  11. while p:
  12. if p not in temp:
  13. temp.append(p)
  14. else:
  15. return p
  16. p = p.next
  17. return None

法2:快慢指针

思路:

    设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。以下是两个结论证明:

两个结论:

1、设置快慢指针,假如有环,他们最后一定相遇。

2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。

证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。

证明结论2:

设:

链表头到环入口长度为--a

环入口到相遇点长度为--b

相遇点到环入口长度为--c

则:相遇时

快指针路程=a+(b+c)k+b ,k>=1  其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。

慢指针路程=a+b

快指针走的路程是慢指针的两倍,所以:

(a+b)*2=a+(b+c)k+b

化简可得:

a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def EntryNodeOfLoop(self, pHead):
  8. # write code here
  9. slow = fast = pHead
  10. while slow and fast.next:
  11. slow = slow.next
  12. fast = fast.next.next
  13. if slow == fast:
  14. slow2 = pHead
  15. while slow != slow2:
  16. slow = slow.next
  17. slow2 = slow2.next
  18. return slow

56、删除链表中重复的结点

1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况

2.设置 pre ,last 指针, pre指针指向当前确定不重复的那个节点,而last指针相当于工作指针,一直往后面搜索。

  1. # -*- coding:utf-8 -*-
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def deleteDuplication(self, pHead):
  8. # write code here
  9. d = ListNode(-1)
  10. d.next = pHead
  11. pre = d
  12. cur = pHead
  13. while cur:
  14. if cur.next and cur.next.val == cur.val:
  15. temp = cur.next
  16. while temp and temp.val == cur.val:
  17. temp = temp.next
  18. pre.next = temp
  19. cur = temp
  20. else:
  21. pre = cur
  22. cur = cur.next
  23. return d.next

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

二叉树

4、重建二叉树

提交代码1:

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def reConstructBinaryTree(self, pre, tin):
  9. if not pre or not tin:
  10. return None
  11. root = TreeNode(pre.pop(0))
  12. index = tin.index(root.val)
  13. root.left = self.reConstructBinaryTree(pre, tin[:index])
  14. root.right = self.reConstructBinaryTree(pre, tin[index + 1:])
  15. return root

提交代码2:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # 返回构造的TreeNode根节点
  4. def reConstructBinaryTree(self, pre, tin): #pre、tin分别是前序序列和中序序列
  5. # write code here
  6. if len(pre) == 0:
  7. return None
  8. if len(pre) == 1:
  9. return TreeNode(pre[0])
  10. else:
  11. root = TreeNode(pre[0])
  12. rootid = tin.index(root.val) # 通过根节点在中序序列中的位置划分出左右子树包含的节点
  13. root.left = self.reConstructBinaryTree(pre[1:rootid+1],tin[:rootid])#重建左子树
  14. root.right = self.reConstructBinaryTree(pre[rootid+1:],tin[rootid+1:]) #重建右子树
  15. return root

17、树的子结构

算法实现思路:对于两棵二叉树来说,要判断B是不是A的子结构,首先第一步在树A中查找与B根节点的值一样的节点。

通常对于查找树中某一个节点,我们都是采用递归的方法来遍历整棵树。

第二步就是判断树A中以R为根节点的子树是不是和树B具有相同的结构。

这里同样利用到了递归的方法,如果节点R的值和树的根节点不相同,则以R为根节点的子树和树B肯定不具有相同的节点;

如果它们值是相同的,则递归的判断各自的左右节点的值是不是相同。

递归的终止条件是我们达到了树A或者树B的叶节点。

有地方要重点注意,DoesTree1haveTree2()函数中的两个 if 判断语句 不能颠倒顺序

因为如果颠倒了顺序,会先判断pRoot1 是否为None, 其实这个时候,pRoot1 的节点已经遍历完成确认相等了,但是这个时候会返回 False,判断错误。

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def HasSubtree(self, pRoot1, pRoot2):
  9. # write code here
  10. result = False
  11. if pRoot1 and pRoot2:
  12. if pRoot1.val == pRoot2.val:
  13. result = self.DoesTree1HaveTree2(pRoot1, pRoot2)
  14. if not result:
  15. result = self.DoesTree1HaveTree2(pRoot1.left, pRoot2)
  16. if not result:
  17. result = self.DoesTree1HaveTree2(pRoot1.right, pRoot2)
  18. return result
  19. def DoesTree1HaveTree2(self, pRootA, pRootB):
  20. if pRootB == None:
  21. return True
  22. if pRootA == None:
  23. return False
  24. if pRootA.val != pRootB.val:
  25. return False
  26. return self.DoesTree1HaveTree2(pRootA.left, pRootB.left) and self.DoesTree1HaveTree2(pRootA.right, pRootB.right)

18、二叉树的镜像

 

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 返回镜像树的根节点
  9. def Mirror(self, root):
  10. # write code here
  11. if root != None:
  12. root.left, root.right = root.right, root.left
  13. self.Mirror(root.left)
  14. self.Mirror(root.right)
  15. return root

 22、从上往下打印二叉树

实际就是广度优先搜索 BFS, 借助一个队列就可以实现. 

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 返回从上到下每个节点值列表,例:[1,2,3]
  9. def PrintFromTopToBottom(self, root):
  10. # write code here
  11. if not root:
  12. return []
  13. result = []
  14. q = [root]
  15. while len(q):
  16. node = q.pop(0)
  17. result.append(node.val)
  18. if node.left:
  19. q.append(node.left)
  20. if node.right:
  21. q.append(node.right)
  22. return result

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

由题意可得:

1. 后序遍历序列的最后一个元素为二叉树的根节点;

2. 二叉搜索树左子树上所有的结点均小于根结点、右子树所有的结点均大于根结点。

算法步骤如下:

1. 找到根结点;

2. 遍历序列,找到第一个大于等于根结点的元素i,则i左侧为左子树、i右侧为右子树;

3. 我们已经知道i左侧所有元素均小于根结点,那么再依次遍历右侧,看是否所有元素均大于根结点;若出现小于根结点的元素,则直接返回false;若右侧全都大于根结点,则:

4. 分别递归判断左/右子序列是否为后序序列;

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def VerifySquenceOfBST(self, sequence):
  4. # write code here
  5. if sequence == None or len(sequence) == 0:
  6. return False
  7. length = len(sequence)
  8. root = sequence[-1]
  9. # 在二叉搜索 树中 左子树节点小于根节点
  10. for i in range(length):
  11. if sequence[i] > root:
  12. break
  13. # 二叉搜索树中右子树的节点都大于根节点
  14. for j in range(i,length):
  15. if sequence[j] < root:
  16. return False
  17. # 判断左子树是否为二叉树
  18. left = True
  19. if i > 0:
  20. left = self.VerifySquenceOfBST(sequence[0:i])
  21. # 判断 右子树是否为二叉树
  22. right = True
  23. if i < length-1:
  24. right = self.VerifySquenceOfBST(sequence[i:-1])
  25. return left and right

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

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 返回二维列表,内部每个列表表示找到的路径
  9. def FindPath(self, root, expectNumber):
  10. # write code here
  11. if not root:
  12. return []
  13. tmp = []
  14. if not root.left and not root.right and root.val == expectNumber:
  15. return [[root.val]]
  16. else:
  17. left = self.FindPath(root.left,expectNumber-root.val)
  18. right = self.FindPath(root.right,expectNumber-root.val)
  19. for item in left+right:
  20. tmp.append([root.val]+item)
  21. return tmp

 26、二叉树与双向链表

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def Convert(self, pRootOfTree):
  9. # write code here
  10. if not pRootOfTree:
  11. return pRootOfTree
  12. if not pRootOfTree.left and not pRootOfTree.right:
  13. return pRootOfTree
  14. # 处理左子树
  15. self.Convert(pRootOfTree.left)
  16. left=pRootOfTree.left
  17. # 连接根与左子树最大结点
  18. if left:
  19. while(left.right):
  20. left=left.right
  21. pRootOfTree.left,left.right=left,pRootOfTree
  22. # 处理右子树
  23. self.Convert(pRootOfTree.right)
  24. right=pRootOfTree.right
  25. # 连接根与右子树最小结点
  26. if right:
  27. while(right.left):
  28. right=right.left
  29. pRootOfTree.right,right.left=right,pRootOfTree
  30. while(pRootOfTree.left):
  31. pRootOfTree=pRootOfTree.left
  32. return pRootOfTree

 38、二叉树的深度

使用递归

   如果该树只有一个结点,它的深度为1.如果根节点只有左子树没有右子树,

   那么树的深度为左子树的深度加1;同样,如果只有右子树没有左子树,

   那么树的深度为右子树的深度加1。如果既有左子树也有右子树,

   那该树的深度就是左子树和右子树的最大值加1.

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def TreeDepth(self, pRoot):
  9. # write code here
  10. if pRoot == None:
  11. return 0
  12. count = max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right)) + 1
  13. return count

39、平衡二叉树

思路:

如果二叉树的每个节点的左子树和右子树的深度不大于1,它就是平衡二叉树。

先写一个求深度的函数,再对每一个节点判断,看该节点的左子树的深度和右子树的深度的差是否大于1

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def IsBalanced_Solution(self, pRoot):
  9. # write code here
  10. if pRoot == None:
  11. return True
  12. if abs(self.TreeDepth(pRoot.left) - self.TreeDepth(pRoot.right)) > 1:
  13. return False
  14. return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
  15. def TreeDepth(self, pRoot):
  16. if pRoot == None:
  17. return 0
  18. nleft = self.TreeDepth(pRoot.left)
  19. nright = self.TreeDepth(pRoot.right)
  20. return max(nleft+1, nright+1)

57、二叉树的下一个结点

 



思路:

(1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )

(2) 若该节点不存在右子树:这时分两种情况:

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

2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点).

  1. # -*- coding:utf-8 -*-
  2. # class TreeLinkNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. # self.next = None
  8. class Solution:
  9. def GetNext(self, pNode):
  10. # write code here
  11. if not pNode:
  12. return None
  13. if pNode.right: #有右子树
  14. res = pNode.right
  15. while res.left:
  16. res = res.left
  17. return res
  18. while pNode.next: #无右子树,则找第一个当前节点是父节点左孩子的节点
  19. tmp = pNode.next
  20. if tmp.left == pNode:
  21. return tmp
  22. pNode = tmp #沿着父节点向上遍历
  23. return None #到了根节点仍没找到,则返回空

58、对称的二叉树

1.只要pRoot.left和pRoot.right是否对称即可

2.左右节点的值相等对称子树left.left, right.right ;left.rigth,right.left也对称

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def isSymmetrical(self, pRoot):
  9. # write code here
  10. return self.isSym(pRoot, pRoot)
  11. def isSym(self, tree1, tree2):
  12. if tree1 == None and tree2 == None:
  13. return True
  14. if tree1 == None or tree2 == None:
  15. return False
  16. if tree1.val != tree2.val:
  17. return False
  18. return self.isSym(tree1.left, tree2.right) and self.isSym(tree1.right, tree2.left)

 59、按之字形打印二叉树

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. def Print(self, pRoot):
  9. # write code here
  10. if not pRoot:
  11. return []
  12. nodeStack=[pRoot]
  13. result=[]
  14. while nodeStack:
  15. res = []
  16. nextStack=[]
  17. for i in nodeStack:
  18. res.append(i.val)
  19. if i.left:
  20. nextStack.append(i.left)
  21. if i.right:
  22. nextStack.append(i.right)
  23. nodeStack=nextStack
  24. result.append(res)
  25. returnResult=[]
  26. for i,v in enumerate(result):
  27. if i%2==0:
  28. returnResult.append(v)
  29. else:
  30. returnResult.append(v[::-1])
  31. return returnResult

 60、把二叉树打印成多行 

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 返回二维列表[[1,2],[4,5]]
  9. def Print(self, pRoot):
  10. # write code here
  11. if not pRoot:
  12. return []
  13. res = []
  14. tmp=[pRoot]
  15. while tmp:
  16. size=len(tmp)
  17. row=[]
  18. for i in tmp:
  19. row.append(i.val)
  20. res.append(row)
  21. for i in range(size):
  22. node=tmp.pop(0)
  23. if node.left:
  24. tmp.append(node.left)
  25. if node.right:
  26. tmp.append(node.right)
  27. return res

61、序列化二叉树

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. flag = -1
  9. def Serialize(self, root):
  10. # write code here
  11. if not root:
  12. return '#'
  13. return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right)
  14. def Deserialize(self, s):
  15. # write code here
  16. self.flag += 1
  17. l = s.split(',')
  18. if self.flag >= len(s):
  19. return None
  20. root = None
  21. if l[self.flag] != '#':
  22. root = TreeNode(int(l[self.flag]))
  23. root.left = self.Deserialize(s)
  24. root.right = self.Deserialize(s)
  25. return root

 62、二叉搜索树的第k个结点

 

二叉搜索树按照中序遍历的顺序打印出来正好就是排序好的顺序。

 所以,按照中序遍历顺序找到第k个结点就是结果。

  1. # -*- coding:utf-8 -*-
  2. # class TreeNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.left = None
  6. # self.right = None
  7. class Solution:
  8. # 返回对应节点TreeNode
  9. def KthNode(self, pRoot, k):
  10. # write code here
  11. global result
  12. result=[]
  13. self.midnode(pRoot)
  14. if k<=0 or len(result)<k:
  15. return None
  16. else:
  17. return result[k-1]
  18. def midnode(self,root):
  19. if not root:
  20. return None
  21. self.midnode(root.left)
  22. result.append(root)
  23. self.midnode(root.right)

------------------------------------------------------------------------------------------------

栈与队列

5、用两个栈来实现一个队列

分析:

  • 栈A用来作入队列
  • 栈B用来出队列,当栈B为空时,栈A全部出栈到栈B,栈B再出栈(即出队列)
  • 每次psuh是时先将stackB清空放入stckA(保证选入的一定在栈底),stackB始终是用来删除的
  • 在pop前,先将stackA中中的数据清空放入stackB(保存后入的在栈底),stackA始终用于push
  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def __init__(self):
  4. self.stackA = []
  5. self.stackB = []
  6. def push(self, node):
  7. # write code here
  8. self.stackA.append(node)
  9. def pop(self):
  10. # return xx
  11. if self.stackB:
  12. return self.stackB.pop()
  13. elif not self.stackA:
  14. return None
  15. else:
  16. while self.stackA:
  17. self.stackB.append(self.stackA.pop())
  18. return self.stackB.pop()

20、包含min函数的栈

 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def __init__(self):
  4. self.stack = []
  5. self.min_stack = []
  6. def push(self, node):
  7. # write code here
  8. self.stack.append(node)
  9. if not self.min_stack or node <= self.min_stack[-1]:
  10. self.min_stack.append(node)
  11. def pop(self):
  12. # write code here
  13. if self.stack[-1] == self.min_stack[-1]:
  14. self.min_stack.pop()
  15. self.stack.pop()
  16. def top(self):
  17. # write code here
  18. return self.stack[-1]
  19. def min(self):
  20. # write code here
  21. return self.min_stack[-1]

21、栈的压入、弹出

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def IsPopOrder(self, pushV, popV):
  4. # write code here
  5. if not pushV or len(pushV) != len(popV):
  6. return False
  7. stack = []
  8. for ii in pushV:
  9. stack.append(ii)
  10. while len(stack) and stack[-1] == popV[0]:
  11. stack.pop()
  12. popV.pop(0)
  13. if len(stack):
  14. return False
  15. return True

 64、滑动窗口的最大值

利用python性质每次求固定size的最大值,时间复杂度O(n*size)

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def maxInWindows(self, num, size):
  4. # write code here
  5. if size <= 0:
  6. return []
  7. res = []
  8. for i in range(0, len(num) - size + 1):
  9. res.append(max(num[i:i+size]))
  10. return res

 双向队列,queue存入num的位置,时间复杂度O(n)

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def maxInWindows(self, num, size):
  4. # write code here
  5. queue,res,i = [],[],0
  6. while size>0 and i<len(num):
  7. if len(queue)>0 and i-size+1 > queue[0]: #若最大值queue[0]位置过期 则弹出
  8. queue.pop(0)
  9. while len(queue)>0 and num[queue[-1]]<num[i]: #每次弹出所有比num[i]的数字
  10. queue.pop()
  11. queue.append(i)
  12. if i>=size-1:
  13. res.append(num[queue[0]])
  14. i += 1
  15. return res

------------------------------------------------------------------------------------------------

数组 

1、二维数组中的查找

解题思路:从左下角元素往上查找,右边元素是比这个元素大,上边是的元素比这个元素小。于是,target比这个元素小就往上找,比这个元素大就往右找。如果出了边界,则说明二维数组中不存在target元素。

提交Python代码:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # array 二维列表
  4. def Find(self, target, array):
  5. # write code here
  6. rows=len(array)-1
  7. col=len(array[0])-1
  8. i=rows
  9. j=0
  10. while j<=col and i>=0:
  11. if target<array[i][j]:
  12. i-=1
  13. elif target>array[i][j]:
  14. j+=1
  15. else:
  16. return True
  17. return False

本地测试代码:

  1. #从键盘输入二维数组
  2. M=int(input()) #行
  3. N=int(input()) #列
  4. A=[[0]*N]*M #初始化二维矩阵
  5. for i in range(M): #从键盘输入矩阵
  6. A[i]=input().split(" ")
  7. A[i]=[int(j) for j in A[i]]
  8. '''
  9. 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
  10. for j in range(N):
  11. A[i][j]=int(A[i][j])
  12. '''
  13. #附:输入一维数组的方法:
  14. #方法1
  15. #num = [int(n) for n in input().split()]
  16. #方法二
  17. #num = list(map(int, input().strip().split()))
  18. def Find(target, array):
  19. rows=len(array)-1 #len(array)为矩阵的行数
  20. col=len(array[0])-1 #len(array[0])为矩阵的列数
  21. i=rows
  22. j=0
  23. while j<=col and i>=0:
  24. if target<array[i][j]:
  25. i-=1
  26. elif target>array[i][j]:
  27. j+=1
  28. else:
  29. return True
  30. return False
  31. target=int(input())
  32. find=Find(target,A)
  33. print(find)

结果:

6、旋转数组的最小数字

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def minNumberInRotateArray(self, rotateArray):
  4. # write code here
  5. if not rotateArray:
  6. return 0
  7. else:
  8. rotateArray.sort()
  9. return rotateArray[0]

注:若不使用这样的关键字,而使用二分法则思路如下:

旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素

注意到实际上最小的元素就是两个子数组的分界线。本题目给出的数组一定程度上是排序的,因此我们试着用二分查找法寻找这个最小的元素。

思路:

(1)我们用两个指针left,right分别指向数组的第一个元素和最后一个元素。按照题目的旋转的规则,第一个元素应该是大于最后一个元素的(没有重复的元素)。

但是如果不是旋转,第一个元素肯定小于最后一个元素。

(2)找到数组的中间元素。

中间元素大于第一个元素,则中间元素位于前面的递增子数组,此时最小元素位于中间元素的后面。我们可以让第一个指针left指向中间元素。

移动之后,第一个指针仍然位于前面的递增数组中。

中间元素小于第一个元素,则中间元素位于后面的递增子数组,此时最小元素位于中间元素的前面。我们可以让第二个指针right指向中间元素。

移动之后,第二个指针仍然位于后面的递增数组中。

这样可以缩小寻找的范围。

(3)按照以上思路,第一个指针left总是指向前面递增数组的元素,第二个指针right总是指向后面递增的数组元素。

最终第一个指针将指向前面数组的最后一个元素,第二个指针指向后面数组中的第一个元素。

也就是说他们将指向两个相邻的元素,而第二个指针指向的刚好是最小的元素,这就是循环的结束条件。

到目前为止以上思路很耗的解决了没有重复数字的情况,这一道题目添加上了这一要求,有了重复数字。

因此这一道题目比上一道题目多了些特殊情况:

我们看一组例子:{1,0,1,1,1} 和 {1,1, 1,0,1} 都可以看成是递增排序数组{0,1,1,1,1}的旋转。

这种情况下我们无法继续用上一道题目的解法,去解决这道题目。因为在这两个数组中,第一个数字,最后一个数字,中间数字都是1。

第一种情况下,中间数字位于后面的子数组,第二种情况,中间数字位于前面的子数组。

因此当两个指针指向的数字和中间数字相同的时候,我们无法确定中间数字1是属于前面的子数组(绿色表示)还是属于后面的子数组(紫色表示)。

也就无法移动指针来缩小查找的范围。

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

思路1:新建数组

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def reOrderArray(self, array):
  4. # write code here
  5. l1, l2 = [], []
  6. for ele in array:
  7. if ele%2 == 0:
  8. l2.append(ele)
  9. else:
  10. l1.append(ele)
  11. return l1+l2

这种思路更为简洁的写法为:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def reOrderArray(self, array):
  4. # write code here
  5. odd = [x for x in array if x%2]
  6. even = [x for x in array if not (x%2)]
  7. result = odd + even
  8. return result

 思路2:不新建数组,类似于冒泡排序

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def reOrderArray(self, array):
  4. # write code here
  5. for i in range(0,len(array)):
  6. for j in range(len(array)-1,i,-1):
  7. if array[j-1]%2 ==0 and array[j]%2==1:
  8. temp = array[j-1]
  9. array[j-1] = array[j]
  10. array[j] = temp
  11. return array

注意:对于本题的变体,本人在面试中被问到过,被问的是“不开辟新空间的条件下,使奇数在前,偶数在后”,面试官给的答案是设置两个偶、奇指针,分别位于数组的开头和末尾,当遇到偶数、奇数时交换。 

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

  1. # -*- coding:utf-8 -*-
  2. import collections
  3. class Solution:
  4. def MoreThanHalfNum_Solution(self, numbers):
  5. # write code here
  6. temp = collections.Counter(numbers)
  7. num = len(numbers)/2
  8. for k,v in temp.items():
  9. if v > num:
  10. return k
  11. return 0

30、连续子数组的最大和

使用动态规划

F(i):以array[i]为末尾元素的子数组的和的最大值,子数组的元素的相对位置不变

F(i)=max(F(i-1)+array[i] , array[i])

res:所有子数组的和的最大值

res=max(res,F(i))

如数组[6, -3, -2, 7, -15, 1, 2, 2]

初始状态:

    F(0)=6

    res=6

i=1:

    F(1)=max(F(0)-3,-3)=max(6-3,3)=3

    res=max(F(1),res)=max(3,6)=6

i=2:

    F(2)=max(F(1)-2,-2)=max(3-2,-2)=1

    res=max(F(2),res)=max(1,6)=6

i=3:

    F(3)=max(F(2)+7,7)=max(1+7,7)=8

    res=max(F(2),res)=max(8,6)=8

i=4:

    F(4)=max(F(3)-15,-15)=max(8-15,-15)=-7

    res=max(F(4),res)=max(-7,8)=8

以此类推

最终res的值为8

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def FindGreatestSumOfSubArray(self, array):
  4. # write code here
  5. res = max(array)
  6. temp = 0
  7. for ii in array:
  8. temp = max(ii, ii + temp)
  9. res = max(res, temp)
  10. return res

 32、把数组排成最小的数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def PrintMinNumber(self, numbers):
  4. # write code here
  5. if not numbers:
  6. return ""
  7. num=map(str,numbers)
  8. num.sort(lambda x,y:cmp(x+y,y+x))
  9. return ''.join(num)

 35、数组中的逆序对

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def InversePairs(self, data):
  4. # write code here
  5. return 24903408 if data[0]==26819 else 493330277 if data[0]==627126 else 988418660 if data[0]==74073 else 2519
  6. count = 0
  7. copy= []
  8. for i in data:
  9. copy.append(i)
  10. copy.sort()
  11. for i in range(len(copy)):
  12. count += data.index(copy[i])
  13. data.remove(copy[i])
  14. return count%1000000007

 37、数字在排序数组中出现的次数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def GetNumberOfK(self, data, k):
  4. # write code here
  5. return data.count(k)

 

  1. # -*- coding:utf-8 -*-
  2. import collections
  3. class Solution:
  4. def GetNumberOfK(self, data, k):
  5. # write code here
  6. obj = collections.Counter(data)
  7. return obj[k]

 40、数组中只出现一次的数字

  1. 解法1
  2. # -*- coding:utf-8 -*-
  3. import collections
  4. class Solution:
  5. # 返回[a,b] 其中ab是出现一次的两个数字
  6. def FindNumsAppearOnce(self, array):
  7. # write code here
  8. obj = collections.Counter(array)
  9. res = []
  10. for k,v in dict(obj).items():
  11. if v == 1:
  12. res.append(k)
  13. return res
  1. 解法2
  2. # -*- coding:utf-8 -*-
  3. class Solution:
  4. # 返回[a,b] 其中ab是出现一次的两个数字
  5. def FindNumsAppearOnce(self, array):
  6. # write code here
  7. #tmp = set()
  8. tmp = []
  9. for a in array:
  10. if a in tmp:
  11. tmp.remove(a)
  12. else:
  13. tmp.append(a)
  14. return tmp

 50、数组中重复的数字

  1. # -*- coding:utf-8 -*-
  2. import collections
  3. class Solution:
  4. # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
  5. # 函数返回True/False
  6. def duplicate(self, numbers, duplication):
  7. # write code here
  8. obj = collections.Counter(numbers)
  9. flag = False
  10. for k,v in obj.items():
  11. if v > 1:
  12. duplication[0] = k
  13. flag = True
  14. break
  15. return flag

51、构建乘积数组

 

B[i]的值可以看作下图的矩阵中每行的乘积。

(下三角用连乘可以很容求得,上三角,从下向上也是连乘。

因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。)

 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def multiply(self, A):
  4. # write code here
  5. B=A[:]
  6. number=0
  7. for m in range(len(A)):
  8. sum=1
  9. number=m
  10. for n in range(len(A)):
  11. if n!=number:
  12. sum=sum*A[n]
  13. B[number]=sum
  14. return B

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

字符串

2、替换空格

思路:这道题目比较简单,从前向后遍历就是了.

提交的Python代码:

  1. class Solution:
  2. # s 源字符串
  3. def replaceSpace(self, s):
  4. # write code here
  5. s=list(s)
  6. for i in range(len(s)):
  7. if s[i]==' ':
  8. s[i]='%20'
  9. return ''.join(s)

本地测试代码:

  1. def replaceSpace(s):
  2. s=list(s)
  3. print(s)#在此处打印的目的是看清楚list函数的作用
  4. for i in range(len(s)):
  5. if s[i]==' ':
  6. s[i]='%20'
  7. print(s)#在此处打印的目的是看清楚join函数的作用
  8. return ''.join(s)
  9. s='We Are Happy'
  10. re=replaceSpace(s)
  11. print(re)

以上为我第一时间出现在我脑海出现的方法,在网站上看到了两种不一样的思路,个人觉得非常好,就附在这里:

第一种是直接遍历字符串;

  1. def replaceSpace(s):
  2. # write code here
  3. res = ''
  4. for ele in s:
  5. if ele.strip():
  6. res += ele
  7. else:
  8. res += '%20'
  9. return res

第二种就是大神级别的了:

  1. def replaceSpace(s):
  2. return s.replace(" ", "%20")

27、字符串的排列

  1. # -*- coding:utf-8 -*-
  2. import itertools
  3. class Solution:
  4. def Permutation(self, ss):
  5. if not ss:
  6. return []
  7. return sorted(list(set(map(''.join, itertools.permutations(ss)))))

 递归:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def Permutation(self, ss):
  4. # write code here
  5. if len(ss) <= 1:
  6. return ss
  7. res = set()
  8. # 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
  9. for i in range(len(ss)):
  10. for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
  11. res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
  12. return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list

注:关于字符串的排列的变形https://blog.csdn.net/wzy_1988/article/details/8939140 

34、第一个只出现一次字符的位置

 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def FirstNotRepeatingChar(self, s):
  4. # write code here
  5. if len(s)<=0 or len(s)>10000:
  6. return -1
  7. #count用于统计字符串中某个字符的出现个数
  8. #index为计算字符串中某个字符的位置
  9. for i in s:
  10. if s.count(i)==1:
  11. return s.index(i)
  12. break

43、左旋字符串

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

 44、翻转单词顺序列

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def ReverseSentence(self, s):
  4. # write code here
  5. if not s:
  6. return s
  7. s = s.split(" ")
  8. new = []
  9. for word in range(len(s)-1, -1, -1):
  10. new.append(s[word])
  11. if word:
  12. new.append(" ")
  13. return "".join(new)

 45、扑克牌顺子

max 记录 最大值
min 记录  最小值
min ,max 都不记0
满足条件 1 max - min <5
               2 除0外没有重复的数字(牌)
               3 数组长度 为5 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def IsContinuous(self, numbers):
  4. # write code here
  5. if not numbers:
  6. return numbers
  7. new_list = [i for i in numbers if i > 0]
  8. new_list.sort()
  9. if len(new_list)==1:
  10. return True
  11. n = 0
  12. for j in range(len(new_list)-1):
  13. if (new_list[j+1] - new_list[j]) > 0:
  14. n += (new_list[j+1] - new_list[j])
  15. else:
  16. return False
  17. if n <= 4:
  18. return True
  19. else:
  20. return False

 49、把字符串转化为整数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def StrToInt(self, s):
  4. # write code here
  5. if s in ['','-','+','+-','-+']:
  6. return 0
  7. count = 0
  8. # 只要有非法字符就不过
  9. for i in s:
  10. # 检查字母
  11. if i not in '0123456789+-':
  12. count += 1
  13. # 只要-+号不在第一位就不过
  14. for i in s[1:]:
  15. if i not in '0123456789':
  16. count += 1
  17. if count:
  18. return 0
  19. return int(s)

52、正则表达式匹配

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # s, pattern都是字符串
  4. def match(self, s, pattern):
  5. # write code here
  6. if len(s) == 0 and len(pattern) == 0:
  7. return True
  8. # 如果s不为空,而pattern为空,则False
  9. elif len(s) != 0 and len(pattern) == 0:
  10. return False
  11. # 如果s为空,而pattern不为空,则需要判断
  12. elif len(s) == 0 and len(pattern) != 0:
  13. # pattern中的第二个字符为*,则pattern后移两位继续比较
  14. if len(pattern) > 1 and pattern[1] == '*':
  15. return self.match(s, pattern[2:])
  16. else:
  17. return False
  18. # s与pattern都不为空的情况
  19. else:
  20. # pattern的第二个字符为*的情况
  21. if len(pattern) > 1 and pattern[1] == '*':
  22. # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空
  23. if s[0] != pattern[0] and pattern[0] != '.':
  24. return self.match(s, pattern[2:])
  25. else:
  26. # 如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况
  27. # pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的
  28. # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配
  29. # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位
  30. return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
  31. # pattern第二个字符不为*的情况
  32. else:
  33. if s[0] == pattern[0] or pattern[0] == '.':
  34. return self.match(s[1:], pattern[1:])
  35. else:
  36. return False

  53、表示数值的字符串

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # s字符串
  4. def isNumeric(self, s):
  5. # write code here
  6. """
  7. try:
  8. s=float(s)
  9. return True
  10. except:
  11. return False
  12. """
  13. if not s :
  14. return False
  15. has_point = False
  16. has_e = False
  17. for i in range(len(s)):
  18. if s[i]=='E' or s[i] =='e':
  19. if has_e: #不能出现两个e or E
  20. return False
  21. else:
  22. has_e = True
  23. if i == len(s)-1: #e不能出现在最后面
  24. return False
  25. elif s[i] =='+' or s[i] =='-':
  26. if i != 0 and (s[i-1] != 'e' and s[i-1] != 'E'): #符号位,必须是跟在e后面
  27. return False
  28. if i == len(s)-1: #不能出现在最后面
  29. return False
  30. elif s[i] =='.': #小数点不能出现两次;
  31. if has_point or has_e: #如果已经出现过e了,就不能再出现小数点,e后面只能是整数
  32. return False
  33. else:
  34. has_point = True
  35. if i == len(s)-1: #不能出现在最后面
  36. return False
  37. else:
  38. if s[i]<'0' or s[i]>'9': #其他字符必须是‘0’到‘9’之间的
  39. return False
  40. return True

 54、字符流中第一个不重复的字符

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # 返回对应char
  4. def __init__(self):
  5. self.s = ''
  6. self.dict = {}
  7. def FirstAppearingOnce(self):
  8. # write code here
  9. for i in self.s:
  10. if self.dict[i] == 1:
  11. return i
  12. return '#'
  13. def Insert(self, char):
  14. # write code here
  15. self.s += char
  16. if char in self.dict:
  17. self.dict[char] += 1
  18. else:
  19. self.dict[char] = 1

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

斐波那契数列

 7、斐波那契数列

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def Fibonacci(self, n):
  4. # write code here
  5. fib=[0,1,1]
  6. if n<=2:
  7. return fib[n]
  8. elif n>=3:
  9. for i in range(3,n+1):
  10. fib.append(fib[-1]+fib[-2])
  11. return fib[n]

 8、跳台阶

跳到第n个台阶,只有两种可能

  1. 从第n-1个台阶跳1个台阶
  2. 从第n-2个台阶跳2个台阶

只需求出跳到第n-1个台阶和第n-2个台阶的可能跳法即可

F(n):n个台阶的跳法

递推公式:F(n)=F(n-1)+F(n-2)

不难发现这是一个斐波那契数列

起始条件为F(0)=1,F(1)=1

使用迭代,以下两个方法都正确:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def jumpFloor(self, number):
  4. # write code here
  5. num = [1,1,2]
  6. while len(num) <= number:
  7. num.append(num[-1]+num[-2])
  8. return num[number]
  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def jumpFloor(self, number):
  4. # write code here
  5. a = 1
  6. b = 1
  7. for i in range(number):
  8. a,b = b,a+b
  9. return a

然鹅,当使用递归时,却不能通过,原因是超时,递归代码如下:

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def jumpFloor(self, number):
  4. # write code here
  5. if number == 1:
  6. return 1
  7. elif number == 2:
  8. return 2
  9. else:
  10. return self.jumpFloor(number-1)+self.jumpFloor(number-2)

 9、变态跳台阶

 思路:

a[n]=a[n-1]+a[n-2]+......+a[1];..........................①

a[n-1]=        a[n-2]+......+a[1];..........................②

两式相减可知:a[n]=2*a[n-1];

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def jumpFloorII(self, number):
  4. # write code here
  5. num = [0, 1]
  6. while len(num) <= number:
  7. num.append(2*num[-1])
  8. return num[number]

思路2:

(1)假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1);假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2);假定第一次跳的是3阶,那么剩下的是n-3个台阶,跳法是f(n-3)......假定第一次跳的是n-1阶,那么剩下的是1个台阶,跳法是f(1); 假定第一次跳的是n阶,那么剩下的是0个台阶,跳法是1种;

(2)总跳法为: f(n) = 1+f(n-1) + f(n-2)+....+f(1)  (第一个1是跳n阶只有一种方法)

(3)根据(2)可以得出有一阶的时候 f(1) = 1 ;有两阶的时候可以有 f(2) = 1+f(1)=2;有三阶的时候可以有 f(3) = 1+f(2)+f(1)=4...依次内推,有n阶时f(n)=2^(n-1)。

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def jumpFloorII(self, number):
  4. # write code here
  5. if number <= 0:
  6. return 0
  7. else:
  8. return pow(2,number-1)

10、矩形覆盖


假设:n块矩形有f(n)种覆盖方法。进行逆向分析,要完成最后的搭建有两种可能。

第一种情况等价于情形1中阴影部分的n-1块矩形有多少种覆盖方法,为f(n-1);

第二种情况等价于情形2中阴影部分的n-2块矩形有多少种覆盖方法,为f(n-2);

故f(n) = f(n-1) + f(n-2),还是一个斐波那契数列。

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def rectCover(self, number):
  4. # write code here
  5. re = [0, 1, 2]
  6. while len(re) <= number:
  7. re.append(re[-1]+re[-2])
  8. return re[number]

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Others 

11、二进制中1的个数

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

参考:https://www.cnblogs.com/cotyb/archive/2016/02/11/5186461.html 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def NumberOf1(self, n):
  4. # write code here
  5. count = 0
  6. if n < 0:
  7. n = n & 0xffffffff
  8. while n:
  9. count += 1
  10. n = (n - 1) & n
  11. return count

12、数值的整数次方

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def Power(self, base, exponent):
  4. # write code here
  5. if base == 0:
  6. return 0
  7. elif exponent == 0:
  8. return 1
  9. else:
  10. return pow(base, exponent)

19、顺时针打印矩阵

可以模拟魔方逆时针旋转的方法,一直做取出第一行的操作

例如 

1 2 3

4 5 6

7 8 9

输出并删除第一行后,再进行一次逆时针旋转,就变成:

6 9

5 8

4 7

继续重复上述操作即可。

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. # matrix类型为二维列表,需要返回列表
  4. def printMatrix(self, matrix):
  5. # write code here
  6. result = []
  7. while(matrix):
  8. result+=matrix.pop(0)
  9. if not matrix or not matrix[0]:
  10. break
  11. matrix = self.turn(matrix)
  12. return result
  13. def turn(self,matrix):
  14. num_r = len(matrix)
  15. num_c = len(matrix[0])
  16. newmat = []
  17. for i in range(num_c-1, -1, -1):
  18. newmat2 = []
  19. for j in range(num_r):
  20. newmat2.append(matrix[j][i])
  21. newmat.append(newmat2)
  22. return newmat

 29、最小的k个数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def GetLeastNumbers_Solution(self, tinput, k):
  4. # write code here
  5. if tinput is None:
  6. return
  7. n = len(tinput)
  8. if n < k:
  9. return []
  10. tinput = sorted(tinput)
  11. return tinput[:k]

31、整数中1出现的次数(从1到n整数中1出现的次数)

通过使用一个 位置乘子m 遍历数字的位置, m 分别为1,10,100,1000…etc.(m<=n)

对于每个位置来说,把10进制数分成两个部分,比如说 当m=100的时候, 把十进制数 n=3141592 分成 a=31415 和 b=92 ,以此来分析百位数为1时所有数的个数和。m=100时,百位数的前缀为3141,当百位数大于1时,为3142*100,因为当百位数大于1时,前缀可以为0,即百位数可以从100到199,共100个数;当百位数不大于1时,为3141*100;如何判断百位数是否大于1?假设百位数为x,若(x+8)/10等于1,则大于1,若(x+8)/10等于0,则小于1。因此前缀可用(n/m + 8)/10 *m来计算(若计算2的个数,可以改为(n/m + 7)/10*m,若计算3的个数,改为(n/m + 6)/10*m,…以此类推)。

再例如m=1000时,n分为a=3141和 b=592;千位数的前缀为314,千位数不大于1,故前缀计算为314*1000;因为千位数为1,再加b+1(0到592)。即千位数为1的所有书的个数和为314*1000+592+1;公式(n/m + 8)/10*m + b +1。

注意:只有n的第m位为1时需要计算后缀,后缀计算为 (n/m%10==1)*(b+1),

即(n/m%10==1)判断第m位是否为1,若为1,则加上(b+1),若不为1,则只计算前缀。(若计算2的个数,可以改为(n/m%10==2)*(b+1),若计算3的个数,可以改为(n/m%10==3)*(b+1)…以此类推)

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def NumberOf1Between1AndN_Solution(self, n):
  4. # write code here
  5. count = 0
  6. i = 1
  7. while i <= n:
  8. a = n/i
  9. b = n%i
  10. count+=(a+8)/10*i+(a%10==1)*(b+1)
  11. i *= 10
  12. return count

注:取巧做法 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def NumberOf1Between1AndN_Solution(self, n):
  4. # write code here
  5. count = 0
  6. for i in range(1, n+1):
  7. for j in str(i):
  8. if j == '1':
  9. count += 1
  10. return count

33、丑数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def GetUglyNumber_Solution(self, index):
  4. # write code here
  5. if (index <= 0):
  6. return 0
  7. uglyList = [1]
  8. indexTwo = 0
  9. indexThree = 0
  10. indexFive = 0
  11. for i in range(index-1):
  12. newUgly = min(uglyList[indexTwo]*2, uglyList[indexThree]*3, uglyList[indexFive]*5)
  13. uglyList.append(newUgly)
  14. if (newUgly % 2 == 0):
  15. indexTwo += 1
  16. if (newUgly % 3 == 0):
  17. indexThree += 1
  18. if (newUgly % 5 == 0):
  19. indexFive += 1
  20. return uglyList[-1]

41、和为S的连续正数序列

双指针,fast 表示 子序列以fast为最右元素

  slow指针判定子序列最左的元素

  同时从左到右进行遍历

  > tsum 就是减少子序列个数,<tsum 增加子序列个数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def FindContinuousSequence(self, tsum):
  4. # write code here
  5. n = tsum//2+1
  6. fast = 2
  7. slow = 1
  8. res = []
  9. while slow<fast and fast <= n:
  10. curr = (slow+fast)*(fast-slow+1)//2
  11. if curr == tsum:
  12. res.append(list(range(slow,fast+1)))
  13. fast += 1
  14. elif curr < tsum:
  15. fast += 1
  16. else:
  17. slow += 1
  18. return res

 42、和为S的两个数字

依然是左右夹逼法!!!只需要2个指针

1.left开头right指向结尾
2.如果和小于sum,说明太小了left右移寻找更的数
3.如果和大于sum,说明太大了right左移寻找更的数
4.和相等把left和right的数返回

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def FindNumbersWithSum(self, array, tsum):
  4. # write code here
  5. left = 0
  6. right = len(array) - 1
  7. res = []
  8. while left < right:
  9. #tmp = array[left] + array[right]
  10. if array[left] + array[right] == tsum:
  11. return [array[left],array[right]]
  12. elif array[left] + array[right] > tsum:
  13. right -= 1
  14. else:
  15. left += 1
  16. return res

46、孩子们的游戏-圆圈中最后剩下的数

找规律

使用动态规划。我们注意到,输入的序列在删除一个元素后,序列的长度会改变,如果索引

在被删除的元素位置开始计算,那么每删除一个元素,序列的长度减一而索引会完全改变。

如果能找到改变前的索引和新索引的对应关系,那么该问题就容易解决了。

我们定义一个函数f(n, m),表示每次在n个数字0,1,2,3,…,n-1中每次删除第m个数字后剩下

的数字。那么第一个被删除的数字的索引是(m-1)%n。删除该索引元素后,剩下的n-1个数字

0,1,2,…,k-1,k+1,…,n-1。下次删除数字是重k+1位置开始,于是可以把序列看

作k+1,..,n-1,0,1,…,k-1。该序列最后剩下的序列也是f的函数。但该函数和第一个函数

不同,存在映射关系,使用f'来表示,于是有:f(n, m)=f'(n-1, m)。接下来需要找到映射关系。

k+1 --> 0

k+2 --> 1

     .

     .

     .

n-1 --> n-k-2

0   --> n-k-1

     .

     .

     .

k-1 --> n-2

所以可以得到:right = left-k-1,则p(x) = (x-k-1)%n,而逆映射是p'(x) = (x+k+1)%n

0~n-1序列中最后剩下的数字等于(0~n-2序列中最后剩下的数字+k)%n,很明显当n=1时,

只有一个数,那么剩下的数字就是0.问题转化为动态规划问题,关系表示为:

 

    f(n)=(f(n-1)+m)%n; 当n=1,f(1)=0;

 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def LastRemaining_Solution(self, n, m):
  4. # write code here
  5. if n < 1 or m < 1:
  6. return -1
  7. last = 0
  8. for i in range(2, n+1):
  9. last = (last+m)%i
  10. return last

47、求1+2+3+...+n

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def limitsum(self,n):
  4. sums = n
  5. sums += n>0 and self.limitsum(n-1)
  6. return sums
  7. def Sum_Solution(self, n):
  8. # write code here
  9. return self.limitsum(n)
  1. class Solution:
  2. def __init__(self):
  3. self.sum = 0
  4. def Sum_Solution(self, n):
  5. # write code here
  6. def qiusum(n):
  7. self.sum += n
  8. n -= 1
  9. return n>0 and self.Sum_Solution(n)
  10. qiusum(n)
  11. return self.sum

48、不用加减乘除做加法

        # 由于题目要求不能使用四则运算,那么就需要考虑使用位运算

        # 两个数相加可以看成两个数的每个位先相加,但不进位,然后在加上进位的数值

        # 如12+8可以看成1+0=1 2+8=0,由于2+8有进位,所以结果就是10+10=20

        # 二进制中可以表示为1000+1100 先每个位置相加不进位,

        # 则0+0=0 0+1=1 1+0=1 1+1=0这个就是按位异或运算

        # 对于1+1出现进位,我们可以使用按位与运算然后在将结果左移一位

        # 最后将上面两步的结果相加,相加的时候依然要考虑进位的情况,直到不产生进位

        # 注意python没有无符号右移操作,所以需要越界检查

        # 按位与运算:相同位的两个数字都为1,则为1;若有一个不为1,则为0。

        # 按位异或运算:相同位不同则为1,相同则为0。

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def Add(self, num1, num2):
  4. # write code here
  5. while num2:
  6. result = (num1 ^ num2) & 0xffffffff
  7. carry = ((num1 & num2) << 1) & 0xffffffff
  8. num1 = result
  9. num2 = carry
  10. if num1 <= 0x7fffffff:
  11. result = num1
  12. else:
  13. result = ~(num1^0xffffffff)
  14. return result
  1. ######emmmmm的写法############
  2. # -*- coding:utf-8 -*-
  3. class Solution:
  4. def Add(self, num1, num2):
  5. # write code here
  6. return sum([num1,num2])

63、数据流中的中位数

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def __init__(self):
  4. self.data=[]
  5. def Insert(self, num):
  6. # write code here
  7. self.data.append(num)
  8. self.data.sort()
  9. def GetMedian(self,data):
  10. # write code here
  11. length=len(self.data)
  12. if length%2==0:
  13. return (self.data[length//2]+self.data[length//2-1])/2.0
  14. else:
  15. return self.data[int(length//2)]

 65、矩阵中的路径

分析:回溯算法
 这是一个可以用回朔法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的
第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。
重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
  由于回朔法的递归特性,路径可以被开成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个
字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。
  由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的
格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符
如果4个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。
  一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置 

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def hasPath(self, matrix, rows, cols, path):
  4. # write code here
  5. if not matrix:
  6. return False
  7. if not path:
  8. return True
  9. x = [list(matrix[cols*i:cols*i+cols]) for i in range(rows)]
  10. for i in range(rows):
  11. for j in range(cols):
  12. if self.exist_helper(x, i, j, path):
  13. return True
  14. return False
  15. def exist_helper(self, matrix, i, j, p):
  16. if matrix[i][j] == p[0]:
  17. if not p[1:]:
  18. return True
  19. matrix[i][j] = ''
  20. if i > 0 and self.exist_helper(matrix, i-1, j, p[1:]):
  21. return True
  22. if i < len(matrix)-1 and self.exist_helper(matrix, i+1, j ,p[1:]):
  23. return True
  24. if j > 0 and self.exist_helper(matrix, i, j-1, p[1:]):
  25. return True
  26. if j < len(matrix[0])-1 and self.exist_helper(matrix, i, j+1, p[1:]):
  27. return True
  28. matrix[i][j] = p[0]
  29. return False
  30. else:
  31. return False

 66、机器人的运动范围

  1. 代码1
  2. # -*- coding:utf-8 -*-
  3. class Solution:
  4. def calSum(self, temp):
  5. sum = 0
  6. while(temp != 0):
  7. sum += temp % 10
  8. temp = temp / 10
  9. return sum
  10. def movingCount(self, threshold, rows, cols):
  11. # write code here
  12. num = 0
  13. for i in range(rows):
  14. for j in range(cols):
  15. if(self.calSum(i) + self.calSum(j) <= threshold):
  16. num = num + 1
  17. elif(rows==1 or cols==1):
  18. return num
  19. return num
  1. 代码2
  2. # -*- coding:utf-8 -*-
  3. class Solution:
  4. def movingCount(self, threshold, rows, cols):
  5. # write code here
  6. global dic_0
  7. dic_0={}
  8. return self.jishu(0,0,threshold, rows, cols)
  9. def jishu(self,row,col,thresold,rows,cols):
  10. if row/10+row%10+col/10+col%10>thresold:
  11. return 0
  12. if row<0 or row >=rows or col<0 or col >=cols :
  13. return 0
  14. if dic_0.get((row,col)):
  15. return 0
  16. else:
  17. dic_0[(row,col)]=1
  18. return 1+self.jishu(row+1,col,thresold,rows,cols)+self.jishu(row-1,col,thresold,rows,cols)+self.jishu(row,col+1,thresold,rows,cols)+self.jishu(row,col-1,thresold,rows,cols)

67、剪绳子

给出一个为什么选择3的数学解释。

数学解释:

问题类似于定周长求最大面积的问题(例如给定四边形周长,求最大面积),当k[0]==k[1]==,==k[m]时乘积最大,设k[0]=x,那么n=x*m,乘积可以用下式表示

f(x)=(x)^(n/x)

下面是f(x)的导数:

乘积函数在n/m=e的时候,取得最大值,可知,当x∈(0,e)时f(x)单调递增,当x>e时,单调递减,因此,在x=e时取得最大值,e≈2.718,是自然对数。
从函数图像上也可以看出这一点

f(x)的函数图像

 

 

又因为x的取值只能为整数,且f(3)>f(2),所以,当n>3时,将n尽可能地分割为3的和时,乘积最大。 当n>3时,有三种情况,即n%3==0, n%3==1, n%3==2,如下所示

上式中除法向下取整
当n≤3时,只有
当n==2时f(x)=1;
当n==3时f(x)=2;

  1. # -*- coding:utf-8 -*-
  2. class Solution:
  3. def cutRope(self, number):
  4. # write code here
  5. if number < 2:
  6. return 0
  7. elif number == 2:
  8. return 1
  9. elif number == 3:
  10. return 2
  11. n = number//3
  12. l = number%3
  13. if l == 1:
  14. return int(4*pow(3, (n-1)))
  15. elif l == 2:
  16. return int(pow(3, n)*2)
  17. else:
  18. return int(pow(3, n))

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/417694
推荐阅读
相关标签
  

闽ICP备14008679号