赞
踩
刷剑指offer的时候只需要提交函数核心部分,但是在公司实际笔试时却需要自己写好输入输出,各个题目的输入也都是五花八门的,在这里记录一下一般常用的输入的写法,以免忘记。
1.输入一维数组
- #输入一维数组的方法:
- # 方法1
- num = [int(n) for n in input().split()]
- print(num)
- # 方法二
- num = list(map(int, input().strip().split()))
- print(num)
这两种输入方法的结果是一样的:
2.输入二维数组
- #输入指定大小的数组
- M = int(input()) # 行
- N = int(input()) # 列
- A = [[0]*N] * M # 初始化二维矩阵
- for i in range(M): # 从键盘输入矩阵
- A[i] = input().split(" ")
- A[i] = [int(j) for j in A[i]]
- '''
- 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
- for j in range(N):
- A[i][j]=int(A[i][j])
- '''
-
- print(A)
- #输入指定行不定列的数组
- M = int(input()) # 行
- A = [[0]] * M # 初始化二维矩阵
- for i in range(M): # 从键盘输入矩阵
- A[i] = input().split(" ")
- A[i] = [int(j) for j in A[i]]
- '''
- 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
- for j in range(N):
- A[i][j]=int(A[i][j])
- '''
-
- print(A)
--------------------------------------------------------------------------------------------------------------------------------------
提交代码1:
最简单是思路是用递归,依次滑动链表指针,让最前的元素保持在最后。
- # -*- 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
- if listNode is None:
- return []
- return self.printListFromTailToHead(listNode.next) + [listNode.val]
提交代码2:
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
-
- class Solution:
- # 返回从尾部到头部的列表值序列,例如[1,2,3]
- def printListFromTailToHead(self, listNode):
- if not listNode:
- return []
- result=[]
- while listNode:
- result.append(listNode.val)
- listNode=listNode.next
- result.reverse()
- return result
提交代码3:
- # -*- coding:utf-8 -*-
- # 运行时间:33ms
- # 占用内存:5852k
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
-
- class Solution:
- # 返回从尾部到头部的列表值序列,例如[1,2,3]
- def printListFromTailToHead(self, listNode):
- if not listNode:
- return []
- res=[]
- result=[]
- while listNode:
- res.append(listNode.val)
- listNode=listNode.next
- while res:
- result.append(res.pop())
- return result
提交代码4:
从头到尾遍历链表,将值存在列表res中,最后将res逆序输出。
- # -*- 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
- res = []
- p = listNode
- while p:
- res.append(p.val)
- p = p.next
- return res[::-1]
题解1:
- class Solution:
- def FindKthToTail(self, head, k):
- # write code here
- if head==None or k<=0:
- return None
- #设置两个指针,p2指针先走(k-1)步,然后再一起走,当p2为最后一个时,p1就为倒数第k个 数
- p2=head
- p1=head
- #p2先走,走k-1步,如果k大于链表长度则返回 空,否则的话继续走
- while k>1:
- if p2.next!=None:
- p2=p2.next
- k-=1
- else:
- return None
- #两个指针一起 走,一直到p2为最后一个,p1即为所求
- while p2.next!=None:
- p1=p1.next
- p2=p2.next
- return p1
题解2:
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
-
- class Solution:
- def FindKthToTail(self, head, k):
- # write code here
- l=[]
- while head!=None:
- l.append(head)
- head=head.next
- if k>len(l) or k<1:
- return None
- return l[-k]
思路:1->2->3->4->5,遍历链表,把1的next置为None,2的next置为1,以此类推,5的next置为4。得到反转链表。需要考虑链表只有1个元素的情况。图中有具体的每步迭代的思路,最后输出pre而不是cur是因为最后一次迭代后cur已经指向None了,而pre是完整的反向链表。
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- # 返回ListNode
- def ReverseList(self, pHead):
- # write code here
- if pHead==None or pHead.next==None:
- return pHead
- pre = None
- cur = pHead
- while cur!=None:
- tmp = cur.next
- cur.next = pre
- pre = cur
- cur = tmp
- return pre
注:此题的进阶是Leetcode第25题:k个一组翻转链表
思路一:栈
- # Definition for singly-linked list.
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
-
- class Solution:
- def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
- dummy = ListNode(0)
- p = dummy
- while True:
- count = k
- stack = []
- tmp = head
- while count and tmp:
- stack.append(tmp)
- tmp = tmp.next
- count -= 1
- # 注意,目前tmp所在k+1位置
- # 说明剩下的链表不够k个,跳出循环
- if count :
- p.next = head
- break
- # 翻转操作
- while stack:
- p.next = stack.pop()
- p = p.next
- #与剩下链表连接起来
- p.next = tmp
- head = tmp
-
- return dummy.next
思路二:递归
- # Definition for singly-linked list.
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
-
- class Solution:
- def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
- cur = head
- count = 0
- while cur and count!= k:
- cur = cur.next
- count += 1
- if count == k:
- cur = self.reverseKGroup(cur, k)
- while count:
- tmp = head.next
- head.next = cur
- cur = head
- head = tmp
- count -= 1
- head = cur
- return head
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- # 返回合并后列表
- def Merge(self, pHead1, pHead2):
- # write code here
- res = head = ListNode(0)
- while pHead1 and pHead2:
- if pHead1.val < pHead2.val:
- head.next = pHead1
- pHead1 = pHead1.next
-
- elif pHead1.val >= pHead2.val:
- head.next = pHead2
- pHead2 = pHead2.next
- head = head.next
- head.next = pHead1 or pHead2
-
- return res.next
递归:
- # -*- coding:utf-8 -*-
- # class RandomListNode:
- # def __init__(self, x):
- # self.label = x
- # self.next = None
- # self.random = None
- class Solution:
- # 返回 RandomListNode
- def Clone(self, pHead):
- # write code here
- if not pHead: return
- newNode = RandomListNode(pHead.label)
- newNode.random = pHead.random
- newNode.next = self.Clone(pHead.next)
- return newNode
哈希表法:
- class Solution:
- def Clone(self, head):
- nodeList = [] #存放各个节点
- randomList = [] #存放各个节点指向的random节点。没有则为None
- labelList = [] #存放各个节点的值
-
- while head:
- randomList.append(head.random)
- nodeList.append(head)
- labelList.append(head.label)
- head = head.next
- #random节点的索引,如果没有则为1
- labelIndexList = map(lambda c: nodeList.index(c) if c else -1, randomList)
-
- dummy = RandomListNode(0)
- pre = dummy
- #节点列表,只要把这些节点的random设置好,顺序串起来就ok了。
- nodeList=map(lambda c:RandomListNode(c),labelList)
- #把每个节点的random绑定好,根据对应的index来绑定
- for i in range(len(nodeList)):
- if labelIndexList[i]!=-1:
- nodeList[i].random=nodeList[labelIndexList[i]]
- for i in nodeList:
- pre.next=i
- pre=pre.next
- return dummy.next
假定 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)
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- def FindFirstCommonNode(self, pHead1, pHead2):
- # write code here
- p1 = pHead1
- p2 = pHead2
-
- while p1 != p2:
- p1 = p1.next if p1 != None else pHead2
- p2 = p2.next if p2 != None else pHead1
- return p1
法1:遍历这个链表,把链表每个元素记录在list里,然后一旦遇到了重复节点则存在环,不然就不存在
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- def EntryNodeOfLoop(self, pHead):
- # write code here
- temp = []
- p = pHead
- while p:
- if p not in temp:
- temp.append(p)
- else:
- return p
- p = p.next
- 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圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- def EntryNodeOfLoop(self, pHead):
- # write code here
- slow = fast = pHead
- while slow and fast.next:
- slow = slow.next
- fast = fast.next.next
- if slow == fast:
- slow2 = pHead
- while slow != slow2:
- slow = slow.next
- slow2 = slow2.next
- return slow
1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况
2.设置 pre ,last 指针, pre指针指向当前确定不重复的那个节点,而last指针相当于工作指针,一直往后面搜索。
- # -*- coding:utf-8 -*-
- # class ListNode:
- # def __init__(self, x):
- # self.val = x
- # self.next = None
- class Solution:
- def deleteDuplication(self, pHead):
- # write code here
- d = ListNode(-1)
- d.next = pHead
- pre = d
- cur = pHead
- while cur:
- if cur.next and cur.next.val == cur.val:
- temp = cur.next
- while temp and temp.val == cur.val:
- temp = temp.next
- pre.next = temp
- cur = temp
- else:
- pre = cur
- cur = cur.next
- return d.next
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
提交代码1:
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
-
- class Solution:
- def reConstructBinaryTree(self, pre, tin):
- if not pre or not tin:
- return None
- root = TreeNode(pre.pop(0))
- index = tin.index(root.val)
- root.left = self.reConstructBinaryTree(pre, tin[:index])
- root.right = self.reConstructBinaryTree(pre, tin[index + 1:])
- return root
提交代码2:
- # -*- coding:utf-8 -*-
- class Solution:
- # 返回构造的TreeNode根节点
- def reConstructBinaryTree(self, pre, tin): #pre、tin分别是前序序列和中序序列
- # write code here
- if len(pre) == 0:
- return None
- if len(pre) == 1:
- return TreeNode(pre[0])
- else:
- root = TreeNode(pre[0])
- rootid = tin.index(root.val) # 通过根节点在中序序列中的位置划分出左右子树包含的节点
- root.left = self.reConstructBinaryTree(pre[1:rootid+1],tin[:rootid])#重建左子树
- root.right = self.reConstructBinaryTree(pre[rootid+1:],tin[rootid+1:]) #重建右子树
- return root
算法实现思路:对于两棵二叉树来说,要判断B是不是A的子结构,首先第一步在树A中查找与B根节点的值一样的节点。
通常对于查找树中某一个节点,我们都是采用递归的方法来遍历整棵树。
第二步就是判断树A中以R为根节点的子树是不是和树B具有相同的结构。
这里同样利用到了递归的方法,如果节点R的值和树的根节点不相同,则以R为根节点的子树和树B肯定不具有相同的节点;
如果它们值是相同的,则递归的判断各自的左右节点的值是不是相同。
递归的终止条件是我们达到了树A或者树B的叶节点。
有地方要重点注意,DoesTree1haveTree2()函数中的两个 if 判断语句 不能颠倒顺序 。
因为如果颠倒了顺序,会先判断pRoot1 是否为None, 其实这个时候,pRoot1 的节点已经遍历完成确认相等了,但是这个时候会返回 False,判断错误。
- # -*- 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
- result = False
- if pRoot1 and pRoot2:
- if pRoot1.val == pRoot2.val:
- result = self.DoesTree1HaveTree2(pRoot1, pRoot2)
- if not result:
- result = self.DoesTree1HaveTree2(pRoot1.left, pRoot2)
- if not result:
- result = self.DoesTree1HaveTree2(pRoot1.right, pRoot2)
- return result
-
- def DoesTree1HaveTree2(self, pRootA, pRootB):
- if pRootB == None:
- return True
- if pRootA == None:
- return False
- if pRootA.val != pRootB.val:
- return False
- return self.DoesTree1HaveTree2(pRootA.left, pRootB.left) and self.DoesTree1HaveTree2(pRootA.right, pRootB.right)
- # -*- 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 root != None:
- root.left, root.right = root.right, root.left
- self.Mirror(root.left)
- self.Mirror(root.right)
- return root
实际就是广度优先搜索 BFS, 借助一个队列就可以实现.
- # -*- 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
- if not root:
- return []
- result = []
- q = [root]
- while len(q):
- node = q.pop(0)
- result.append(node.val)
- if node.left:
- q.append(node.left)
- if node.right:
- q.append(node.right)
- return result
由题意可得:
1. 后序遍历序列的最后一个元素为二叉树的根节点;
2. 二叉搜索树左子树上所有的结点均小于根结点、右子树所有的结点均大于根结点。
算法步骤如下:
1. 找到根结点;
2. 遍历序列,找到第一个大于等于根结点的元素i,则i左侧为左子树、i右侧为右子树;
3. 我们已经知道i左侧所有元素均小于根结点,那么再依次遍历右侧,看是否所有元素均大于根结点;若出现小于根结点的元素,则直接返回false;若右侧全都大于根结点,则:
4. 分别递归判断左/右子序列是否为后序序列;
- # -*- coding:utf-8 -*-
- class Solution:
- def VerifySquenceOfBST(self, sequence):
- # write code here
- if sequence == None or len(sequence) == 0:
- return False
- length = len(sequence)
- root = sequence[-1]
- # 在二叉搜索 树中 左子树节点小于根节点
- for i in range(length):
- if sequence[i] > root:
- break
- # 二叉搜索树中右子树的节点都大于根节点
- for j in range(i,length):
- if sequence[j] < root:
- return False
- # 判断左子树是否为二叉树
- left = True
- if i > 0:
- left = self.VerifySquenceOfBST(sequence[0:i])
- # 判断 右子树是否为二叉树
- right = True
- if i < length-1:
- right = self.VerifySquenceOfBST(sequence[i:-1])
- return left and right
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
- class Solution:
- # 返回二维列表,内部每个列表表示找到的路径
- def FindPath(self, root, expectNumber):
- # write code here
- if not root:
- return []
- tmp = []
- if not root.left and not root.right and root.val == expectNumber:
- return [[root.val]]
- else:
- left = self.FindPath(root.left,expectNumber-root.val)
- right = self.FindPath(root.right,expectNumber-root.val)
- for item in left+right:
- tmp.append([root.val]+item)
- return tmp
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
- class Solution:
- def Convert(self, pRootOfTree):
- # write code here
- if not pRootOfTree:
- return pRootOfTree
- if not pRootOfTree.left and not pRootOfTree.right:
- return pRootOfTree
- # 处理左子树
- self.Convert(pRootOfTree.left)
- left=pRootOfTree.left
-
- # 连接根与左子树最大结点
- if left:
- while(left.right):
- left=left.right
- pRootOfTree.left,left.right=left,pRootOfTree
-
- # 处理右子树
- self.Convert(pRootOfTree.right)
- right=pRootOfTree.right
-
- # 连接根与右子树最小结点
- if right:
- while(right.left):
- right=right.left
- pRootOfTree.right,right.left=right,pRootOfTree
-
- while(pRootOfTree.left):
- pRootOfTree=pRootOfTree.left
- return pRootOfTree
使用递归
如果该树只有一个结点,它的深度为1.如果根节点只有左子树没有右子树,
那么树的深度为左子树的深度加1;同样,如果只有右子树没有左子树,
那么树的深度为右子树的深度加1。如果既有左子树也有右子树,
那该树的深度就是左子树和右子树的最大值加1.
- # -*- 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
- if pRoot == None:
- return 0
- count = max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right)) + 1
- return count
思路:
如果二叉树的每个节点的左子树和右子树的深度不大于1,它就是平衡二叉树。
先写一个求深度的函数,再对每一个节点判断,看该节点的左子树的深度和右子树的深度的差是否大于1
- # -*- 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
- 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):
- if pRoot == None:
- return 0
- nleft = self.TreeDepth(pRoot.left)
- nright = self.TreeDepth(pRoot.right)
- return max(nleft+1, nright+1)
思路:
(1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )
(2) 若该节点不存在右子树:这时分两种情况:
2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D )
2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,知道找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 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 not pNode:
- return None
- if pNode.right: #有右子树
- res = pNode.right
- while res.left:
- res = res.left
- return res
- while pNode.next: #无右子树,则找第一个当前节点是父节点左孩子的节点
- tmp = pNode.next
- if tmp.left == pNode:
- return tmp
- pNode = tmp #沿着父节点向上遍历
- return None #到了根节点仍没找到,则返回空
1.只要pRoot.left和pRoot.right是否对称即可
2.左右节点的值相等且对称子树left.left, right.right ;left.rigth,right.left也对称
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
- class Solution:
- def isSymmetrical(self, pRoot):
- # write code here
- return self.isSym(pRoot, pRoot)
-
- def isSym(self, tree1, tree2):
- if tree1 == None and tree2 == None:
- return True
- if tree1 == None or tree2 == None:
- return False
- if tree1.val != tree2.val:
- return False
- return self.isSym(tree1.left, tree2.right) and self.isSym(tree1.right, tree2.left)
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
- class Solution:
- def Print(self, pRoot):
- # write code here
- if not pRoot:
- return []
- nodeStack=[pRoot]
- result=[]
- while nodeStack:
- res = []
- nextStack=[]
- for i in nodeStack:
- res.append(i.val)
- if i.left:
- nextStack.append(i.left)
- if i.right:
- nextStack.append(i.right)
- nodeStack=nextStack
- result.append(res)
- returnResult=[]
- for i,v in enumerate(result):
- if i%2==0:
- returnResult.append(v)
- else:
- returnResult.append(v[::-1])
- return returnResult
- # -*- 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):
- # write code here
- if not pRoot:
- return []
- res = []
- tmp=[pRoot]
- while tmp:
- size=len(tmp)
- row=[]
- for i in tmp:
- row.append(i.val)
- res.append(row)
- for i in range(size):
- node=tmp.pop(0)
- if node.left:
- tmp.append(node.left)
- if node.right:
- tmp.append(node.right)
- return res
- # -*- coding:utf-8 -*-
- # class TreeNode:
- # def __init__(self, x):
- # self.val = x
- # self.left = None
- # self.right = None
- class Solution:
- 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.flag += 1
-
- l = s.split(',')
- if self.flag >= len(s):
- return None
-
- root = None
- if l[self.flag] != '#':
- root = TreeNode(int(l[self.flag]))
- root.left = self.Deserialize(s)
- root.right = self.Deserialize(s)
- return root
二叉搜索树按照中序遍历的顺序打印出来正好就是排序好的顺序。
所以,按照中序遍历顺序找到第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)
分析:
- # -*- coding:utf-8 -*-
- class Solution:
- def __init__(self):
- self.stackA = []
- self.stackB = []
-
- def push(self, node):
- # write code here
- self.stackA.append(node)
-
- def pop(self):
- # return xx
- if self.stackB:
- return self.stackB.pop()
- elif not self.stackA:
- return None
- else:
- while self.stackA:
- self.stackB.append(self.stackA.pop())
- return self.stackB.pop()
- # -*- coding:utf-8 -*-
- class Solution:
- def __init__(self):
- self.stack = []
- self.min_stack = []
- def push(self, node):
- # write code here
- self.stack.append(node)
- if not self.min_stack or node <= self.min_stack[-1]:
- self.min_stack.append(node)
- def pop(self):
- # write code here
- 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]
- # -*- coding:utf-8 -*-
- class Solution:
- def IsPopOrder(self, pushV, popV):
- # write code here
- if not pushV or len(pushV) != len(popV):
- return False
- stack = []
- for ii in pushV:
- stack.append(ii)
- while len(stack) and stack[-1] == popV[0]:
- stack.pop()
- popV.pop(0)
-
- if len(stack):
- return False
- return True
利用python性质每次求固定size的最大值,时间复杂度O(n*size)
- # -*- coding:utf-8 -*-
- 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
双向队列,queue存入num的位置,时间复杂度O(n)
- # -*- coding:utf-8 -*-
- class Solution:
- def maxInWindows(self, num, size):
- # write code here
- queue,res,i = [],[],0
- while size>0 and i<len(num):
- if len(queue)>0 and i-size+1 > queue[0]: #若最大值queue[0]位置过期 则弹出
- queue.pop(0)
- while len(queue)>0 and num[queue[-1]]<num[i]: #每次弹出所有比num[i]的数字
- queue.pop()
- queue.append(i)
- if i>=size-1:
- res.append(num[queue[0]])
- i += 1
- return res
解题思路:从左下角元素往上查找,右边元素是比这个元素大,上边是的元素比这个元素小。于是,target比这个元素小就往上找,比这个元素大就往右找。如果出了边界,则说明二维数组中不存在target元素。
提交Python代码:
- # -*- coding:utf-8 -*-
- class Solution:
- # array 二维列表
- def Find(self, target, array):
- # write code here
- rows=len(array)-1
- col=len(array[0])-1
- i=rows
- j=0
- while j<=col and i>=0:
- if target<array[i][j]:
- i-=1
- elif target>array[i][j]:
- j+=1
- else:
- return True
- return False
本地测试代码:
- #从键盘输入二维数组
- M=int(input()) #行
- N=int(input()) #列
- A=[[0]*N]*M #初始化二维矩阵
- for i in range(M): #从键盘输入矩阵
- A[i]=input().split(" ")
- A[i]=[int(j) for j in A[i]]
- '''
- 此处还有第二种写法,可将A[i]=[int(j) for j in A[i]]替换为:
- for j in range(N):
- A[i][j]=int(A[i][j])
- '''
- #附:输入一维数组的方法:
- #方法1
- #num = [int(n) for n in input().split()]
- #方法二
- #num = list(map(int, input().strip().split()))
-
- def Find(target, array):
- rows=len(array)-1 #len(array)为矩阵的行数
- col=len(array[0])-1 #len(array[0])为矩阵的列数
- i=rows
- j=0
- while j<=col and i>=0:
- if target<array[i][j]:
- i-=1
- elif target>array[i][j]:
- j+=1
- else:
- return True
- return False
-
- target=int(input())
- find=Find(target,A)
- print(find)
结果:
- # -*- coding:utf-8 -*-
- class Solution:
- def minNumberInRotateArray(self, rotateArray):
- # write code here
- if not rotateArray:
- return 0
- else:
- rotateArray.sort()
- 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是属于前面的子数组(绿色表示)还是属于后面的子数组(紫色表示)。
也就无法移动指针来缩小查找的范围。
思路1:新建数组
- # -*- coding:utf-8 -*-
- class Solution:
- def reOrderArray(self, array):
- # write code here
- l1, l2 = [], []
- for ele in array:
- if ele%2 == 0:
- l2.append(ele)
- else:
- l1.append(ele)
- return l1+l2
这种思路更为简洁的写法为:
- # -*- coding:utf-8 -*-
- class Solution:
- def reOrderArray(self, array):
- # write code here
- odd = [x for x in array if x%2]
- even = [x for x in array if not (x%2)]
- result = odd + even
- return result
思路2:不新建数组,类似于冒泡排序
- # -*- coding:utf-8 -*-
- class Solution:
- def reOrderArray(self, array):
- # write code here
- for i in range(0,len(array)):
- for j in range(len(array)-1,i,-1):
- if array[j-1]%2 ==0 and array[j]%2==1:
- temp = array[j-1]
- array[j-1] = array[j]
- array[j] = temp
- return array
注意:对于本题的变体,本人在面试中被问到过,被问的是“不开辟新空间的条件下,使奇数在前,偶数在后”,面试官给的答案是设置两个偶、奇指针,分别位于数组的开头和末尾,当遇到偶数、奇数时交换。
- # -*- coding:utf-8 -*-
- import collections
- class Solution:
- def MoreThanHalfNum_Solution(self, numbers):
- # write code here
- temp = collections.Counter(numbers)
- num = len(numbers)/2
- for k,v in temp.items():
- if v > num:
- return k
- return 0
使用动态规划
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
- # -*- coding:utf-8 -*-
- class Solution:
- def FindGreatestSumOfSubArray(self, array):
- # write code here
- res = max(array)
- temp = 0
- for ii in array:
- temp = max(ii, ii + temp)
- res = max(res, temp)
- return res
- # -*- coding:utf-8 -*-
- class Solution:
- def PrintMinNumber(self, numbers):
- # write code here
- if not numbers:
- return ""
- num=map(str,numbers)
- num.sort(lambda x,y:cmp(x+y,y+x))
- return ''.join(num)
- # -*- coding:utf-8 -*-
- class Solution:
- def InversePairs(self, data):
- # write code here
- return 24903408 if data[0]==26819 else 493330277 if data[0]==627126 else 988418660 if data[0]==74073 else 2519
- count = 0
- copy= []
- for i in data:
- copy.append(i)
- copy.sort()
- for i in range(len(copy)):
- count += data.index(copy[i])
- data.remove(copy[i])
- return count%1000000007
- # -*- coding:utf-8 -*-
- class Solution:
- def GetNumberOfK(self, data, k):
- # write code here
- return data.count(k)
- # -*- coding:utf-8 -*-
- import collections
- class Solution:
- def GetNumberOfK(self, data, k):
- # write code here
- obj = collections.Counter(data)
- return obj[k]
- 解法1:
- # -*- coding:utf-8 -*-
- import collections
- class Solution:
- # 返回[a,b] 其中ab是出现一次的两个数字
- def FindNumsAppearOnce(self, array):
- # write code here
- obj = collections.Counter(array)
- res = []
- for k,v in dict(obj).items():
- if v == 1:
- res.append(k)
- return res
- 解法2:
- # -*- coding:utf-8 -*-
- class Solution:
- # 返回[a,b] 其中ab是出现一次的两个数字
- def FindNumsAppearOnce(self, array):
- # write code here
- #tmp = set()
- tmp = []
- for a in array:
- if a in tmp:
- tmp.remove(a)
- else:
- tmp.append(a)
- return tmp
- # -*- coding:utf-8 -*-
- import collections
- class Solution:
- # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
- # 函数返回True/False
- def duplicate(self, numbers, duplication):
- # write code here
- obj = collections.Counter(numbers)
- flag = False
- for k,v in obj.items():
- if v > 1:
- duplication[0] = k
- flag = True
- break
- return flag
B[i]的值可以看作下图的矩阵中每行的乘积。
(下三角用连乘可以很容求得,上三角,从下向上也是连乘。
因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。)
- # -*- coding:utf-8 -*-
- class Solution:
- def multiply(self, A):
- # write code here
- B=A[:]
- number=0
- for m in range(len(A)):
- sum=1
- number=m
- for n in range(len(A)):
- if n!=number:
- sum=sum*A[n]
- B[number]=sum
- return B
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
思路:这道题目比较简单,从前向后遍历就是了.
提交的Python代码:
- class Solution:
- # s 源字符串
- def replaceSpace(self, s):
- # write code here
- s=list(s)
- for i in range(len(s)):
- if s[i]==' ':
- s[i]='%20'
- return ''.join(s)
本地测试代码:
- def replaceSpace(s):
- s=list(s)
- print(s)#在此处打印的目的是看清楚list函数的作用
- for i in range(len(s)):
- if s[i]==' ':
- s[i]='%20'
- print(s)#在此处打印的目的是看清楚join函数的作用
- return ''.join(s)
-
- s='We Are Happy'
- re=replaceSpace(s)
- print(re)
以上为我第一时间出现在我脑海出现的方法,在网站上看到了两种不一样的思路,个人觉得非常好,就附在这里:
第一种是直接遍历字符串;
- def replaceSpace(s):
- # write code here
- res = ''
- for ele in s:
- if ele.strip():
- res += ele
- else:
- res += '%20'
- return res
第二种就是大神级别的了:
- def replaceSpace(s):
- return s.replace(" ", "%20")
- # -*- coding:utf-8 -*-
- import itertools
- class Solution:
- def Permutation(self, ss):
- if not ss:
- return []
- return sorted(list(set(map(''.join, itertools.permutations(ss)))))
递归:
- # -*- coding:utf-8 -*-
- class Solution:
- def Permutation(self, ss):
- # write code here
- if len(ss) <= 1:
- return ss
- res = set()
- # 遍历字符串,固定第一个元素,第一个元素可以取a,b,c...,然后递归求解
- for i in range(len(ss)):
- for j in self.Permutation(ss[:i] + ss[i+1:]): # 依次固定了元素,其他的全排列(递归求解)
- res.add(ss[i] + j) # 集合添加元素的方法add(),集合添加去重(若存在重复字符,排列后会存在相同,如baa,baa)
- return sorted(res) # sorted()能对可迭代对象进行排序,结果返回一个新的list
注:关于字符串的排列的变形https://blog.csdn.net/wzy_1988/article/details/8939140
- # -*- coding:utf-8 -*-
- class Solution:
- def FirstNotRepeatingChar(self, s):
- # write code here
- if len(s)<=0 or len(s)>10000:
- return -1
- #count用于统计字符串中某个字符的出现个数
- #index为计算字符串中某个字符的位置
- for i in s:
- if s.count(i)==1:
- return s.index(i)
- break
- # -*- coding:utf-8 -*-
- class Solution:
- def LeftRotateString(self, s, n):
- # write code here
- return s[n:] + s[:n]
- # -*- coding:utf-8 -*-
- class Solution:
- def ReverseSentence(self, s):
- # write code here
- if not s:
- return s
- s = s.split(" ")
- new = []
- for word in range(len(s)-1, -1, -1):
- new.append(s[word])
- if word:
- new.append(" ")
- return "".join(new)
max 记录 最大值
min 记录 最小值
min ,max 都不记0
满足条件 1 max - min <5
2 除0外没有重复的数字(牌)
3 数组长度 为5
- # -*- coding:utf-8 -*-
- class Solution:
- def IsContinuous(self, numbers):
- # write code here
- if not numbers:
- return numbers
- new_list = [i for i in numbers if i > 0]
- new_list.sort()
- if len(new_list)==1:
- return True
- n = 0
- for j in range(len(new_list)-1):
- if (new_list[j+1] - new_list[j]) > 0:
- n += (new_list[j+1] - new_list[j])
- else:
- return False
- if n <= 4:
- return True
- else:
- return False
- # -*- coding:utf-8 -*-
- class Solution:
- def StrToInt(self, s):
- # write code here
- if s in ['','-','+','+-','-+']:
- return 0
- count = 0
- # 只要有非法字符就不过
- for i in s:
- # 检查字母
- if i not in '0123456789+-':
- count += 1
- # 只要-+号不在第一位就不过
- for i in s[1:]:
- if i not in '0123456789':
- count += 1
- if count:
- return 0
- return int(s)
- # -*- coding:utf-8 -*-
- class Solution:
- # s, pattern都是字符串
- def match(self, s, pattern):
- # write code here
- 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
- # -*- coding:utf-8 -*-
- class Solution:
- # s字符串
- def isNumeric(self, s):
- # write code here
- """
- try:
- s=float(s)
- return True
- except:
- return False
- """
- if not s :
- return False
- has_point = False
- has_e = False
- for i in range(len(s)):
- if s[i]=='E' or s[i] =='e':
- if has_e: #不能出现两个e or E
- return False
- else:
- has_e = True
- if i == len(s)-1: #e不能出现在最后面
- return False
- elif s[i] =='+' or s[i] =='-':
- if i != 0 and (s[i-1] != 'e' and s[i-1] != 'E'): #符号位,必须是跟在e后面
- return False
- if i == len(s)-1: #不能出现在最后面
- return False
- elif s[i] =='.': #小数点不能出现两次;
- if has_point or has_e: #如果已经出现过e了,就不能再出现小数点,e后面只能是整数
- return False
- else:
- has_point = True
- if i == len(s)-1: #不能出现在最后面
- return False
- else:
- if s[i]<'0' or s[i]>'9': #其他字符必须是‘0’到‘9’之间的
- return False
- return True
- # -*- coding:utf-8 -*-
- class Solution:
- # 返回对应char
- def __init__(self):
- self.s = ''
- self.dict = {}
- def FirstAppearingOnce(self):
- # write code here
- for i in self.s:
- if self.dict[i] == 1:
- return i
- return '#'
- def Insert(self, char):
- # write code here
- self.s += char
- if char in self.dict:
- self.dict[char] += 1
- else:
- self.dict[char] = 1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- # -*- coding:utf-8 -*-
- class Solution:
- def Fibonacci(self, n):
- # write code here
- fib=[0,1,1]
- if n<=2:
- return fib[n]
- elif n>=3:
- for i in range(3,n+1):
- fib.append(fib[-1]+fib[-2])
- return fib[n]
跳到第n个台阶,只有两种可能
只需求出跳到第n-1个台阶和第n-2个台阶的可能跳法即可
F(n):n个台阶的跳法
递推公式:F(n)=F(n-1)+F(n-2)
不难发现这是一个斐波那契数列
起始条件为F(0)=1,F(1)=1
使用迭代,以下两个方法都正确:
- # -*- coding:utf-8 -*-
- class Solution:
- def jumpFloor(self, number):
- # write code here
- num = [1,1,2]
- while len(num) <= number:
- num.append(num[-1]+num[-2])
- return num[number]
- # -*- coding:utf-8 -*-
- class Solution:
- def jumpFloor(self, number):
- # write code here
- a = 1
- b = 1
- for i in range(number):
- a,b = b,a+b
- return a
然鹅,当使用递归时,却不能通过,原因是超时,递归代码如下:
- # -*- coding:utf-8 -*-
- class Solution:
- def jumpFloor(self, number):
- # write code here
- if number == 1:
- return 1
- elif number == 2:
- return 2
- else:
- return self.jumpFloor(number-1)+self.jumpFloor(number-2)
思路:
a[n]=a[n-1]+a[n-2]+......+a[1];..........................①
a[n-1]= a[n-2]+......+a[1];..........................②
两式相减可知:a[n]=2*a[n-1];
- # -*- coding:utf-8 -*-
- class Solution:
- def jumpFloorII(self, number):
- # write code here
- num = [0, 1]
- while len(num) <= number:
- num.append(2*num[-1])
- 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)。
- # -*- coding:utf-8 -*-
- class Solution:
- def jumpFloorII(self, number):
- # write code here
- if number <= 0:
- return 0
- else:
- return pow(2,number-1)
假设:n块矩形有f(n)种覆盖方法。进行逆向分析,要完成最后的搭建有两种可能。
第一种情况等价于情形1中阴影部分的n-1块矩形有多少种覆盖方法,为f(n-1);
第二种情况等价于情形2中阴影部分的n-2块矩形有多少种覆盖方法,为f(n-2);
故f(n) = f(n-1) + f(n-2),还是一个斐波那契数列。
- # -*- coding:utf-8 -*-
- class Solution:
- def rectCover(self, number):
- # write code here
- re = [0, 1, 2]
- while len(re) <= number:
- re.append(re[-1]+re[-2])
- return re[number]
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对于负数,最高位为1,而负数在计算机是以补码存在的,往右移,符号位不变,符号位1往右移,最终可能会出现全1的情况,导致死循环。与0xffffffff相与,就可以消除负数的影响。
参考:https://www.cnblogs.com/cotyb/archive/2016/02/11/5186461.html
- # -*- coding:utf-8 -*-
- class Solution:
- def NumberOf1(self, n):
- # write code here
- count = 0
- if n < 0:
- n = n & 0xffffffff
- while n:
- count += 1
- n = (n - 1) & n
- return count
- # -*- coding:utf-8 -*-
- class Solution:
- def Power(self, base, exponent):
- # write code here
- if base == 0:
- return 0
- elif exponent == 0:
- return 1
- else:
- return pow(base, exponent)
可以模拟魔方逆时针旋转的方法,一直做取出第一行的操作
例如
1 2 3
4 5 6
7 8 9
输出并删除第一行后,再进行一次逆时针旋转,就变成:
6 9
5 8
4 7
继续重复上述操作即可。
- # -*- coding:utf-8 -*-
- 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-1, -1, -1):
- newmat2 = []
- for j in range(num_r):
- newmat2.append(matrix[j][i])
- newmat.append(newmat2)
- return newmat
- # -*- coding:utf-8 -*-
- class Solution:
- def GetLeastNumbers_Solution(self, tinput, k):
- # write code here
- if tinput is None:
- return
- n = len(tinput)
- if n < k:
- return []
- tinput = sorted(tinput)
- return tinput[:k]
通过使用一个 位置乘子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)…以此类推)
- # -*- coding:utf-8 -*-
- class Solution:
- def NumberOf1Between1AndN_Solution(self, n):
- # write code here
- count = 0
- i = 1
- while i <= n:
- a = n/i
- b = n%i
- count+=(a+8)/10*i+(a%10==1)*(b+1)
- i *= 10
- return count
注:取巧做法
- # -*- coding:utf-8 -*-
- class Solution:
- def NumberOf1Between1AndN_Solution(self, n):
- # write code here
- count = 0
- for i in range(1, n+1):
- for j in str(i):
- if j == '1':
- count += 1
- return count
- # -*- coding:utf-8 -*-
- class Solution:
- def GetUglyNumber_Solution(self, index):
- # write code here
- if (index <= 0):
- return 0
- uglyList = [1]
- indexTwo = 0
- indexThree = 0
- indexFive = 0
- for i in range(index-1):
- newUgly = min(uglyList[indexTwo]*2, uglyList[indexThree]*3, uglyList[indexFive]*5)
- uglyList.append(newUgly)
- if (newUgly % 2 == 0):
- indexTwo += 1
- if (newUgly % 3 == 0):
- indexThree += 1
- if (newUgly % 5 == 0):
- indexFive += 1
- return uglyList[-1]
双指针,fast 表示 子序列以fast为最右元素
slow指针判定子序列最左的元素
同时从左到右进行遍历
> tsum 就是减少子序列个数,<tsum 增加子序列个数
- # -*- coding:utf-8 -*-
- class Solution:
- def FindContinuousSequence(self, tsum):
- # write code here
- n = tsum//2+1
- fast = 2
- slow = 1
- res = []
- while slow<fast and fast <= n:
- curr = (slow+fast)*(fast-slow+1)//2
- if curr == tsum:
- res.append(list(range(slow,fast+1)))
- fast += 1
- elif curr < tsum:
- fast += 1
- else:
- slow += 1
- return res
依然是左右夹逼法!!!只需要2个指针
1.left开头,right指向结尾
2.如果和小于sum,说明太小了,left右移寻找更大的数
3.如果和大于sum,说明太大了,right左移寻找更小的数
4.和相等,把left和right的数返回
- # -*- coding:utf-8 -*-
- class Solution:
- def FindNumbersWithSum(self, array, tsum):
- # write code here
- left = 0
- right = len(array) - 1
- res = []
- while left < right:
- #tmp = array[left] + array[right]
- if array[left] + array[right] == tsum:
- return [array[left],array[right]]
- elif array[left] + array[right] > tsum:
- right -= 1
- else:
- left += 1
- return res
找规律
使用动态规划。我们注意到,输入的序列在删除一个元素后,序列的长度会改变,如果索引
在被删除的元素位置开始计算,那么每删除一个元素,序列的长度减一而索引会完全改变。
如果能找到改变前的索引和新索引的对应关系,那么该问题就容易解决了。
我们定义一个函数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
;
- # -*- coding:utf-8 -*-
- class Solution:
- def LastRemaining_Solution(self, n, m):
- # write code here
- if n < 1 or m < 1:
- return -1
- last = 0
- for i in range(2, n+1):
- last = (last+m)%i
- return last
- # -*- coding:utf-8 -*-
- class Solution:
- def limitsum(self,n):
- sums = n
- sums += n>0 and self.limitsum(n-1)
- return sums
-
- def Sum_Solution(self, n):
- # write code here
- return self.limitsum(n)
- class Solution:
- def __init__(self):
- self.sum = 0
- def Sum_Solution(self, n):
- # write code here
- def qiusum(n):
- self.sum += n
- n -= 1
- return n>0 and self.Sum_Solution(n)
-
- qiusum(n)
- return self.sum
# 由于题目要求不能使用四则运算,那么就需要考虑使用位运算
# 两个数相加可以看成两个数的每个位先相加,但不进位,然后在加上进位的数值
# 如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。
- # -*- coding:utf-8 -*-
- class Solution:
- def Add(self, num1, num2):
- # write code here
- while num2:
- result = (num1 ^ num2) & 0xffffffff
- carry = ((num1 & num2) << 1) & 0xffffffff
- num1 = result
- num2 = carry
- if num1 <= 0x7fffffff:
- result = num1
- else:
- result = ~(num1^0xffffffff)
- return result
- ######emmmmm的写法############
- # -*- coding:utf-8 -*-
- class Solution:
- def Add(self, num1, num2):
- # write code here
- return sum([num1,num2])
- # -*- coding:utf-8 -*-
- class Solution:
- def __init__(self):
- self.data=[]
- def Insert(self, num):
- # write code here
- self.data.append(num)
- self.data.sort()
- def GetMedian(self,data):
- # write code here
- length=len(self.data)
- if length%2==0:
- return (self.data[length//2]+self.data[length//2-1])/2.0
- else:
- return self.data[int(length//2)]
分析:回溯算法
这是一个可以用回朔法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第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个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。
一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置
- # -*- coding:utf-8 -*-
- class Solution:
- def hasPath(self, matrix, rows, cols, path):
- # write code here
- if not matrix:
- return False
- if not path:
- return True
- x = [list(matrix[cols*i:cols*i+cols]) for i in range(rows)]
- for i in range(rows):
- for j in range(cols):
- if self.exist_helper(x, i, j, path):
- return True
- return False
- def exist_helper(self, matrix, i, j, p):
- if matrix[i][j] == p[0]:
- if not p[1:]:
- return True
- matrix[i][j] = ''
- if i > 0 and self.exist_helper(matrix, i-1, j, p[1:]):
- return True
- if i < len(matrix)-1 and self.exist_helper(matrix, i+1, j ,p[1:]):
- return True
- if j > 0 and self.exist_helper(matrix, i, j-1, p[1:]):
- return True
- if j < len(matrix[0])-1 and self.exist_helper(matrix, i, j+1, p[1:]):
- return True
- matrix[i][j] = p[0]
- return False
- else:
- return False
- 代码1:
- # -*- coding:utf-8 -*-
- class Solution:
- def calSum(self, temp):
- sum = 0
- while(temp != 0):
- sum += temp % 10
- temp = temp / 10
- return sum
-
- def movingCount(self, threshold, rows, cols):
- # write code here
- num = 0
- for i in range(rows):
- for j in range(cols):
- if(self.calSum(i) + self.calSum(j) <= threshold):
- num = num + 1
- elif(rows==1 or cols==1):
- return num
- return num
- 代码2:
- # -*- coding:utf-8 -*-
- class Solution:
- def movingCount(self, threshold, rows, cols):
- # write code here
-
- global dic_0
- dic_0={}
- return self.jishu(0,0,threshold, rows, cols)
- def jishu(self,row,col,thresold,rows,cols):
-
- if row/10+row%10+col/10+col%10>thresold:
- return 0
- if row<0 or row >=rows or col<0 or col >=cols :
- return 0
- if dic_0.get((row,col)):
- return 0
- else:
- dic_0[(row,col)]=1
- 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)
给出一个为什么选择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;
- # -*- coding:utf-8 -*-
- class Solution:
- def cutRope(self, number):
- # write code here
- if number < 2:
- return 0
- elif number == 2:
- return 1
- elif number == 3:
- return 2
- n = number//3
- l = number%3
- if l == 1:
- return int(4*pow(3, (n-1)))
- elif l == 2:
- return int(pow(3, n)*2)
- else:
- return int(pow(3, n))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。