一、二维数组的查找
思路1、从二维数组的右上角的元素开始判断,因为此元素是它所在行的最大数,是它所在的列的最小数。如果它等于要查找的数字,则查找过程结束。如果它大于要查找的数字,则可以排除它所在的列。如果它小于要查找的数字,则可排除它所在的行。这样如果要查找的数字不在数组的右上角,则每次判断都可以排除一行或一列以缩小查找范围,直到找到要查找的数字,或者查找范围为空。
# -*- coding:utf-8 -*-
class Solution:
# array 二维列表
def Find(self,num,array):
row = 0
col = len(array[0])-1
if array == None:
return False
while row<len(array) and col >=0:
if array[row][col] == num:
return True
elif array[row][col] > num:
col -=1
else:
row +=1
return False
#339ms 5840k
思路2:遍历一遍
class Solution:
# array 二维列表
def Find(self,num,array):
for row in array:
for j in row:
if num==j:
return True
return False
#331ms 5708k
参考:https://blog.csdn.net/jackmcgradylee/article/details/77871569
二、重建二叉树
递归思路:前序遍历=“根左右”,中序遍历=“左根右”。
由前序遍历序列获得根节点及其位置——>由根节点和对应位置,分别获得:左子树的前序遍历序列和中序遍历序列,以及右子树的前序遍历序列和中序遍历序列——>分别递归左子树的前中序列,右子树的前中序列
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
if len(pre)==0:
return None
if len(pre)==1:
return TreeNode(pre[0])
else:
root=TreeNode(pre[0])
root.left=self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tin[:tin.index(pre[0])])
root.right=self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tin[tin.index(pre[0])+1:])
return root
#56ms 5632k
三、用两个栈实现队列
思路一、stack1用于push,再判断stack2是否为空,如果为空,则将stack1的所有的数据pop出来,压入stack2中,pop sack2,否则直接pop stack2
#29ms 5624k
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1=[]
self.stack2=[]
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2==[]:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
return self.stack2.pop()
参考:https://www.cnblogs.com/wanghui9072229/archive/2011/11/22/2259391.html
四、二叉树的下一个节点
思路1:
1.二叉树为空,则返回空;
2.如果一个节点有右子树,那么它的下一个节点就是它的右子树中的最左子节点
3.如果一个节点没有右子树:如果节点是它的父节点的左节点,那么它的下一个节点就是它的父节点,如果节点是它的父节点的右节点,沿着父节点的指针一直向上遍历,直到找到一个是它父节点的左子节点的节点。
# -*- coding:utf-8 -*-
# class TreeLinkNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# self.next = None
class Solution:
def GetNext(self, pNode):
if not pNode:
return None
if pNode.right:
pNode=pNode.right
while pNode.left:
pNode=pNode.left
return pNode
else:
while pNode.next:
if pNode==pNode.next.left:
return pNode.next
pNode=pNode.next
return None
五、链表中倒数第K个节点
思路1:遍历一次链表获得链表长度,再次遍历链表,至n-k+1个输出
#这是我写的代码,很垃圾
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindKthToTail(self, head, k):
if head==None or k<=0:
return None
node=head
num1=1
while node.next!=None:
node=node.next
num1=num1+1
if k>num1:
return None
num2=0
node2=head
while num2<num1-k:
num2=num2+1
node2=node2.next
return node2
#网上找的代码,写的还不错
class Solution:
def FindKthToTail(self, head, k):
# write code here
if head == None or k <= 0:
return None
p = head
n = 1
while p.next != None:
p = p.next
n = n+1
if k > n:
return None
for i in range(n-k):
head = head.next
return head
思路2:设置2个指针,第一个指针走K-1步之后,第二个指针开始从头走,这样两个指针之间始终相隔K,当指针2走到链表结尾时,指针1的位置即倒数K个节点
思路推广:寻找中间节点, 两个指针一起, 第一个指针每次走两步, 第二个指针每次走一步, 快指针指到尾部, 慢指针正好指到中间
class Solution:
def FindKthToTail(self, head, k):
# write code here
if head == None or k <= 0:
return None
p1 = head
p2 = head
for i in range(k-1):
if p1.next == None:
return None
p1 = p1.next
while p1.next != None:
p1 = p1.next
p2 = p2.next
return p2
---------------------
作者:slibra_L
来源:CSDN
原文:https://blog.csdn.net/slibra_L/article/details/78176540
版权声明:本文为博主原创文章,转载请附上博文链接!
六、反转链表
思路:建立三个变量,L、M、R互相赋值迭代,并建立指向关系,从而实现单链表的反转。这里为什么要设置三个变量,是因为只设置两个变量的话,会出现断开的情况
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
if pHead==None:
return None
L,M,R=None,None,pHead
while R!=None:
L=M
M=R
R=R.next
M.next=L
M.next=L
return M
七、合并两个排序的链表
思路1:
#递归
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
if not pHead1:
return pHead2
if not pHead2:
return pHead1
if pHead1.val<pHead2.val:
pHead1.next=self.Merge(pHead1.next,pHead2)
return pHead1
else:
pHead2.next=self.Merge(pHead1,pHead2.next)
return pHead2
思路2:非递归,Low)
找到两个链表中头节点值相对更小的链表,将其作为主链表,第二个链表中的元素则不断加入到主链表中。具体策略是:主链表定义两个指针,指向两个相邻的元素。当第二个链表中的元素值小于主链表中第二个指针时,将第二个链表的当前元素插入到主链表两个指针指向的元素中间,并调整指针指向。
def Merge(self, pHead1, pHead2):
if not pHead1:
return pHead2
if not pHead2:
return pHead1
mainHead = pHead1 if pHead1.val <= pHead2.val else pHead2
secHead = pHead2 if mainHead == pHead1 else pHead1
mergeHead = mainHead
mainNext = mainHead.next
while mainNext and secHead:
if secHead.val <= mainNext.val:
mainHead.next = secHead
secHead = secHead.next
mainHead.next.next = mainNext
mainHead = mainHead.next
else:
mainHead = mainNext
mainNext = mainNext.next
if not mainNext:
mainHead.next = secHead
return mergeHead
八、矩形覆盖问题
思路1:我们采用从能够简单到复杂的思路思考这个问题,当n=1的时候,只有一个2*1的矩形,所以只有一种方法,记为f(1)=1;当n=2的时候,是两个2*1的矩形,这时候具有两种方式去覆盖这个矩形了(这时候应该是一个正方形),一种是竖着放,一种是横着放,所以有两种方法,记为f(2)=2;
当n=3的时候,仍然只能采用横着放或者竖着放的方式去覆盖这个矩形,我们仍首先考虑使用竖着放的方式,当竖着放的时候,由于已经覆盖了左边(假设是从左边开始覆盖的,从右边的覆盖的效果是一样的)一个2*1的矩形,所以还有2个2*1的矩形,而这种情况我们已经在n=2的时候计算出来了,就是f(2);接下来我们考虑横着放的情况,由于是横着放,在水平方向已经覆盖了一个2*1的矩形,所以要想覆盖这由3个2*1组成的矩形,只能在水平方向的覆盖的那个矩形下面继续覆盖一个,那么只剩下一个2*1的矩形了,这也通过前面的分析计算出来了,就是f(1)。综合以上分析,当n=3的时候,覆盖的方法是f(3)=f(1)+f(2)。
其他以此类推,我们发现这仍然是一个斐波那契数列,所以我们写出如下代码(已被牛客AC):
或者:n=1 - 只有横放一个矩形一种解决办法
n=2 - 有横放一个矩形,竖放两个矩形两种解决办法
n=3 - n=2的基础上加1个横向,n=1的基础上加2个竖向
n=4 - n=3的基础上加1个横向,n=2的基础上加2个竖向
#动态规划
class Solution:
def rectCover(self, number):
if number<=0:
return 0
res=[1,2]
if number>=3:
for i in range(3,number+1):
res.append(res[-1]+res[-2])
return res[number-1]
九、旋转数组的最小数字
思路:这道题最直观的解法并不难,从头到尾遍历数组一次,我们就能找出最小的元素。这种思路的时间复杂度显然是O(n)。但是这个思路没有利用输入的旋转数组的特性,肯定达不到面试官的要求。
我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还注意到最小的元素刚好是这两个子数组的分界线。在排序的数组中我们可以用二分查找法实现O(logn)的查找。
Step1.和二分查找法一样,我们用两个指针分别指向数组的第一个元素和最后一个元素。
Step2.接着我们可以找到数组中间的元素:
如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一个指针仍然位于前面的递增子数组之中。如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。此时该数组中最小的元素应该位于该中间元素的前面。
Step3.接下来我们再用更新之后的两个指针,重复做新一轮的查找。
按照上述的思路,第一个指针总是指向前面递增数组的元素,而第二个指针总是指向后面递增数组的元素。最终第一个指针将指向前面子数组的最后一个元素,而第二个指针会指向后面子数组的第一个元素。也就是它们最终会指向两个相邻的元素,而第二个指针指向的刚好是最小的元素。这就是循环结束的条件。
class Solution:
def minNumberInRotateArray(self, rotateArray):
if len(rotateArray)<=0:
return 0
low=0
high=len(rotateArray)-1
while low<high:
if rotateArray[low]<rotateArray[high]:
return rotateArray[low]
mid=(high-low)//2+low
if rotateArray[mid]>rotateArray[high]:
low=mid+1
else:
high=mid
return rotateArray[low]
10 树的子结构
思路1:需要两个函数,一个用来判断是不是子结构,另外一个是用来进行初始化。
判断是否是子结构的时候,如果当前值相等,需要进行左右值是否相等的判断;如果当前值不等,则判断Root1的左右子树是否包含Root2.
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
if pRoot1==None or pRoot2==None:
return False
return self.issubtree(pRoot1,pRoot2)
def issubtree(self,p1,p2):
res=False
if p2==None:
return True
if p1==None:
return p1==p2
if p1.val==p2.val:
res= self.issubtree(p1.left,p2.left) and self.issubtree(p1.right,p2.right)
return res or self.issubtree(p1.left,p2) or self.issubtree(p1.right,p2)
思路2:https://www.cnblogs.com/GF66/p/9785465.html