41.题目描述
找出所有和为S的连续正数序列
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。
思路:
知识点:数学,前缀和,滑动窗口。
先指定高低两个指针分别等于1和2,若总和<S,则高指针+1;若总和>S,则低指针+1。
滑动窗口方法
时间复杂度:O(N)
空间复杂度:O(1)
class Solution:
def FindContinuousSequence(self, tsum):
lowIndex = 1
highIndex = 2
res = []
while highIndex > lowIndex:
sum = int((highIndex + lowIndex) * (highIndex - lowIndex + 1) / 2) # 求和公式
if sum == tsum:
curSqr = range(lowIndex, highIndex+1)
res.append(curSqr)
lowIndex += 1
elif sum < tsum:
highIndex += 1
else:
lowIndex += 1
return res
s = Solution()
t = s.FindContinuousSequence(60) # tsum=60
print (t)
枚举法
时间复杂度:O(N^3)
空间复杂度:O(1)
class Solution:
def FindContinuousSequence(self, tsum):
if tsum<3:
return [] # tsum小于3的直接不用考虑
result = []
for i in range(1,(tsum+1)/2): # 穷举的话遍历到1/2即可
tem = []
count = 0
while count <tsum:
tem.append(i)
count+=i
i+=1
if count ==tsum:
result.append(tem)
# 使用内置函数进行排序
result.sort()
return result
1.题目描述:
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:
考察点:数组,二分查找
简要说明:这是一道对二维数组进行二分查找的算法,考察对二分查找的灵活运用。把二分值定在右上角或者左下角,就可以进行二分。
从左下角元素往上查找,右边元素是比这个元素大,上边是的元素比这个元素小。于是,target比这个元素小就往上找,比这个元素大就往右找。如果出了边界,则说明二维数组中不存在target元素。
二分法
复杂度分析
时间复杂度:O(m+n) ,其中m为行数,n为列数,最坏情况下,需要遍历m+n次。
空间复杂度:O(1)
class Solution:
def Find(self, target, array):
rows = len(array) - 1
cols= len(array[0]) - 1
i = rows
j = 0
while j<=cols and i>=0:
if target<array[i][j]:
i -= 1
elif target>array[i][j]:
j += 1
else:
return True
return False
array = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 10, 7]]
target =10
solution = Solution()
print (solution.Find(target, array))
2.题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”
考察点:字符串
join()函数:
复杂度分析
时间复杂度:O(length) 只遍历了一遍字符串
空间复杂度:O(1) 没有开辟空间
class Solution:
def replaceSpace(self, s):
return "%20".join(list(s.split(" "))) # 返回值:返回一个以分隔符sep连接各个元素后生成的字符串
s = 'We Are Happy.'
solution =Solution()
print (solution.replaceSpace(s))
直接替换,replace()函数
def replaceSpace(self, s):
return s.replace(" ","%20")
正则表达式
import re
class Solution:
def replaceSpace(self, s):
s=re.sub(r" ","%20",s) # 三个必选参数, 用20%替换空格,s为将要被更改的语句
return s
3.题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路:
这是一道对单链表遍历的入门算法题。
考察点:单链表,递归,反转链表
方法一:遍历并使用insert()函数
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
arrList = []
while (listNode != None):
arrList.insert(0, listNode.val)
listNode = listNode.next
return arrList
solution = Solution()
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4
print (solution.printListFromTailToHead(node1))
方法二 使用栈
class ListNode:
def __init__(self, x): # 初始化实例的值,self为实例
self.val = x
self.next = None
class Solution:
def printListFromTailToHead(self, listNode):
if not listNode:
return []
temp = []
result = []
while listNode:
temp.append(listNode.val) # 进栈
listNode = listNode.next # 将listNode后移一个节点
while temp:
result.append(temp.pop()) # 出栈
return result
方法三 使用从头到尾遍历,逆序输出
class ListNode:
def __init__(self, x): # 初始化实例的值,self为实例
self.val = x
self.next = None
class Solution:
def printListFromTailToHead(self, listNode):
result = []
while listNode:
result.append(listNode.val)
listNode = listNode.next
return result[::-1]
solution = Solution()
node1 = ListNode(1)
node2 = ListNode(2)
node3 = ListNode(3)
node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4
print (solution.printListFromTailToHead(node1))
4.题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
这道题综合考察了对二叉树的前序,中序遍历算法的理解,和根据数组建立二叉树的代码考察以及对递归代码的理解与运用。
考察知识:树,递归。
二叉树的前序遍历:根左右
二叉树的中序遍历:左根右
二叉树的的后序遍历:左右根
思路
首先从前序遍历中拿出第一个,其一定是根节点对应的值,然后以其为分界点将中序遍历分为left和right两部分对应其左子树和右子树,然后将left和right当做新的中序遍历的结果,从前序遍历中拿出前len(left)个当做新的左子树的前序遍历结果,拿出后len(right)当做新的右子树的前序遍历结果,递归求解其left和right对应的二叉树,这样最终即可恢复整棵树。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def reConstructBinaryTree(self, pre, tin):
root = []
if len(pre)==0:
return None # 递归终止条件
elif len(pre)==1:
return TreeNode(pre[0]) # 递归终止条件
else:
root=TreeNode(pre[0])
tinL=tin[:tin.index(pre[0])] # 左子树的中序
tinR=tin[tin.index(pre[0])+1:] # 右子树的中序
root.left=self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tinL) # 左子树的前序,中序
root.right=self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tinR) # 右子树的前序,中序
return root
solution = Solution()
pre = [1, 2, 4, 3, 5, 6] # 前序
tin = [4, 2, 1, 5, 3, 6] # 中序
headNode = solution.reConstructBinaryTree(pre, tin)
print (headNode)
5.题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
这是一道对栈和队列之间灵活转化的题目。
考察知识:队列,栈
解题思路
首先明确栈和数值的特点:
栈:先入后出
人数:先入先出
所以这道题本质上就是使用两个先入后出实现一个先入先出,就是简单的负负得正的道理。
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
self.stack1.append(node)
def pop(self):
self.stack2 = []
while len(self.stack1) != 1:
self.stack2.append(self.stack1.pop()) # self.stack2 = [4,3,2]
node = self.stack1.pop() # node = [1]
while self.stack2:
self.stack1.append(self.stack2.pop()) #self.stack1 = [2,3,4]
return node
solution = Solution()
solution.push(1)
solution.push(2)
solution.push(3)
solution.push(4)
print (solution.pop()) # node = [1]
print (solution.pop()) # 第二次调用函数,node = [2]
print (solution.pop())
print (solution.pop())
6.题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组[3,4,5,1,2]为[1,2,3,4,5]的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
描述
这是一道对二分查找算法灵活运用的一道题目。
二分查找算法不限于运用在有序数组上。如果能够明确二分之后,答案存在于二分的某一侧,就可以使用二分。本题就是如此。
考察知识:数组,二分查找
思路
保证rotateArray[left]为全场最小,当rotateArray[left]<rotateArray[right]时,证明进入了有序数组,直接输出
class Solution:
def minNumberInRotateArray(self, rotateArray):
if len(rotateArray)==0:
return 0
left=0
right=len(rotateArray)-1
while left<right:
if rotateArray[left]<rotateArray[right]:
return rotateArray[left] # 进入了有序数组,直接输出
mid=left+(right-left)//2 # 向下取整
#左边有序取另一半
if rotateArray[left]<rotateArray[mid]:
left=mid+1
#右边有序右边取最小
elif rotateArray[mid]<rotateArray[right]:
right=mid
#前面两个相等的时候,left进一继续
else :
left+=1
return rotateArray[left]
solution = Solution()
print (solution.minNumberInRotateArray([4,5,6,7,1,2,3,4]))
7.题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。n<=39。
考察知识:递归,记忆化搜索,动态规划和动态规划的空间优化。
题目分析
斐波那契数列公式为:f[n] = f[n-1] + f[n-2], 初始值f[0]=0, f[1]=1,目标求f[n]。
方法一 递归函数方式
时间复杂度:O(2^n)
空间复杂度:递归栈的空间
class Solution:
def Fibonacci(self, n):
if n == 0:
return 0
elif n == 1 or n == 2:
return 1
else:
return self.Fibonacci(n-1)+self.Fibonacci(n-2)
n=20
solution = Solution()
print (solution.Fibonacci(n))
方法二 采用三个变量,动态规划。不用递归的过程,直接从子树求得答案。过程是从下往上。
时间复杂度:O(n), 没有重复的计算
空间复杂度:O(n)
class Solution:
def Fibonacci(self, n):
if n < 2:
return n
first = 0
second = 1
result = 1
for i in range(2,n):
first = second
second = result
result = first + second
return result # 当n=2时不执行for循环,result=1
n=20
solution = Solution()
print (solution.Fibonacci(n))
8.题目描述(同7,斐波那契数列)
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
考察知识:递归,记忆化搜索,动态规划和动态规划的空间优化。
解释:
我们把n级台阶时的跳法看成n的函数,记为f(n)。
当n>=2时,第一次跳的时候有两种不同的选择:
第一次跳1级,此时跳法的数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);
第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。
因此,n级台阶的不同跳法总数为f(n) = f(n-1) + f(n-2)
class Solution:
def jumpFloor(self, number):
#此题与菲波那切数列的本质一致
if number == 1:
return 1
if number == 2:
return 2
fOne = 1
fTwo = 2
for i in range(3,number+1):
fN = fTwo + fOne
fOne = fTwo
fTwo = fN
return fN
solution = Solution()
print (solution. jumpFloor(3))
9.题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
这是一道可以递归,记忆化递归,动态规划,递推思想的题目。
分析:
f[n] = f[n-1] + f[n-2] + … + f[0]
f[n-1] = f[n-2] + f[n-3] + … + f[0]
f[n] = 2*f[n-1]
初始条件f[0] = f[1] = 1
f[2] = 2 = 2**1
f[3] = 4 = 2**2
f[4] = 8 = 2**3
…
f[n] = 2**n-1
class Solution:
def jumpFloorII(self, number):
if number == 0:
return 1
else:
return 2**(number-1)
solution = Solution()
print (solution.jumpFloorII(4))
10.题目描述(同7,斐波那契数列)
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2n的大矩形,总共有多少种方法?比如n=3时,23的矩形块有3种覆盖方法。
描述:这是一道规律题。
知识点:递归,记忆递归,动态规划,递推。
分析
从n=3到n=4,怎么来的呢?
这里有2种情况:
直接在n=3的情况下,再后面中添加一个竖着的。这个很显然成立,有3种情况。
然后横着的显然能添加到n-2的情况上,也就是在n=2后面,添加2个横着的,有2种情况。
通过以上分析,发现f [4]=5
所以总结:f [n]表示2*n大矩阵 的方法数。
可以得出:f[n] = f[n-1] + f[n-2],初始条件f[1] = 1, f[2] =2,此题与菲波那切数列的本质一致。
class Solution:
def rectCover(self, number):
#此题与菲波那切数列的本质一致
if number == 0:
return 0
if number == 1:
return 1
if number == 2:
return 2
fOne = 1
fTwo = 2
for i in range(3,number+1): # 确定循环次数
fN = fTwo + fOne
fOne = fTwo
fTwo = fN
return fN
solution = Solution()
print (solution.rectCover(4))