1.数组中重复数字
给定长度为n数组,数组中所有数字都在0-n-1范围内
哈希表时间复杂度太高
用元素值作为位置索引的值,与该元素所在位置的值判断相不相等。
list[I]==list[list[I]]? list[i]:swap(list[i],list[list[i]])
def findCommon(arr):
for i in range(len(arr)):
while arr[i]!=i:
if arr[i]==arr[arr[i]]:
return arr[i]
else:
temp=arr[i]
arr[i]=arr[temp]
arr[temp]=temp
return False
2.不修改数组找出重复数字
在一个长度为n+1的数组里的所有数字都在1-n的范围内,所以数组中至少有一个数字是重复的。
方法:二分查找,查找的依据是小于middle的数字在数组中出现数量和middle-1的大小比较
def count(arr,b):
count=0
for _ in arr:
if _<b:
count+=1
return count
def findCommon1(arr):
start,end=1,len(arr)
while start<=end:
middle=((end-start)>>1)+start
if count(arr,middle)<=middle-1:
start=middle+1
else:
end=middle-1
if end==start and count(arr,start)>1:
return start
return False
3.最长不重复子串,返回长度以及子串
用一个字典记录字母出现的最新位置索引,start记载当前起始位置,当同一个字母第二次出现时,start从该字母第一次出现的位置往后移1
def longestUncommon(ss):
start,maxlength=0,0
used_dict={}
flag=0
for i in range(len(ss)):
if ss[i] in used_dict and start<=used_dict[ss[i]]:
start=used_dict[ss[i]]+1
else:
if maxlength<i-start+1:
maxlength=i-start+1
flag=start
# maxlength=max(maxlength,i-start+1)
used_dict[ss[i]]=i
return maxlength,ss[flag:flag+maxlength]
时间复杂度:o(n)
def getmaxSub(ss):
max_str=ss[0]
for i in range(len(ss)):
temp_str=ss[i]
for j in range(i+1,len(ss)):
if ss[j] not in temp_str:
temp_str+=ss[j]
else:
break
if len(temp_str)>len(max_str):
max_str=temp_str
return max_str
#此方法时间复杂度o(n*n)
4.最大乘积连续数列
例如[-1,-2,3,-4],返回24
经典动态规划问题,定义一维数组难以处理,需要二维数组,第二维有0,1即可,一个记录当前最大值,一个记录当前最小值。
def maxSubstr(nums):
if nums is None:
return 0
dp=[[0 for _ in range(2)] for _ in range(2)]
dp[0][1],dp[0][0],res=nums[0],nums[0],nums[0]
for i in range(len(nums)):
x,y=i%2,(i-1)%2
dp[x][0]=max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
dp[x][1]=min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
print(dp[x][0],dp[x][1])
res=max(res,dp[x][0])
return res
5.零钱兑换
类似爬楼梯问题
def coinChange(arr,amount):
dp=[_ for _ in range(amount+1)]
for i in range(1,amount+1):
for j in range(len(arr)):
if arr[j]<=i:
dp[i]=min(dp[i],dp[i-arr[j]]+1)
if dp[amount]>amount:
return -1
else:
return dp[amount]
6.最小编辑距离
动态规划
def minDistance(word1,word2):
m,n=len(word1),len(word2)
dp=[[0 for _ in range(n+1)] for _ in range(m+1)]
for i in range(m+1): dp[i][0]=i
for j in range(n+1): dp[0][j]=j
for i in range(1,m+1):
for j in range(1,n+1):
dp[i][j]=min(dp[i-1][j-1]+(0 if word1[i-1]==word2[j-1] else 1),
dp[i-1][j]+1,
dp[i][j-1]+1)
return dp[m][n]
7.滑动窗口中的最大值
def maxSlidWindow(arr,k):
res=[]
n=len(arr)
qmax=[]
for i in range(n):
while len(qmax)!=0 and arr[qmax[-1]]<=arr[i]:
qmax.pop()
qmax.append(i)
if qmax[0]==i-k:
qmax.pop(0)
if i>=k-1:
res.append(arr[qmax[0]])
return res
arr=[1,3,-1,-3,5,3,6]
print(maxSlidWindow(arr,3))
8.数组中的逆序对
#归并排序思想将复杂度降低到nlogn
def merge_sort(li):
if len(li)==1:
return li
mid=len(li)//2
left=li[:mid]
right=li[mid:]
ll=merge_sort(left)
lr=merge_sort(right)
return merge(ll,lr)
count=0
def merge(left,right):
global count
result=[]
l,r=0,0
while l<len(left) and r<len(right):
if left[l]<=right[r]:
result.append(left[l])
l+=1
else:
result.append(right[r])
r+=1
count+=len(left)-l
result+=left[l:]
result+=right[r:]
return result
arr=[7,5,6,4]
print(merge_sort(arr))
print(count)
9.二叉树的下一个节点
解题方法
分析二叉树的下一个节点,一共有以下情况:
1.二叉树为空,则返回空;
2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;
3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。
class Node:
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
10.数组中出现次数超过一半的数字
数组中有一个数字出现次数超过一半,也就是说明它出现的次数比其它所有数字出现次数的和还要多。
def getNum(arr):
num=arr[0]
count=1
for i in range(1,len(arr)):
if arr[i]!=num:
if count!=0:
count-=1
else:
num=arr[i]
count=1
else:
count+=1
return num
11.连续子数组的最大和
动态规划
def maxSub(arr):
before=arr[0]
result=arr[0]
for i in range(1,len(arr)):
before=max(before+arr[i],arr[i])
if before>result:
result=before
return result
arr=[1,-2,3,10,-4,7,2,-5]
print(maxSub(arr))
12.数字序列中某一位的数字
def findNthDigit(n):
if n<0:
return -1
len_number = 1
while True:
numbers = 9 * pow(10, len_number-1) #len_number位的数字有多少个
if n <= numbers*len_number:
a = (n-1)/len_number
b = (n-1)%len_number
num = pow(10, len_number-1)+a
for i in range(len_number-1-b):
num = num/10
return int(num%10)
n = n-len_number*numbers
len_number+=1
return -1
print(findNthDigit(5))
13.把数组排成最小的数
变为字符串,然后比较a+b和b+a的大小,从而进行顺序调整,并输出结果
def sortStr(ss1,ss2):
if ss1+ss2>ss2+ss1:
return True
return False
def minNum(arr):
arr=[str(_) for _ in arr]
for i in range(len(arr)):
for j in range(i,len(arr)):
if sortStr(arr[i],arr[j]):
arr[i],arr[j]=arr[j],arr[i]
res=""
for ss in arr:
res+=ss
return res
arr=[3,32,321]
print(minNum(arr))
14. decode way (字符串解码)
动态规划,类似爬楼梯,步长为1或者2
def numDecodings(s):
dp = [0] * (len(s) + 1)
dp[0] = 1
for i in range(1, len(dp)):
if s[i-1] != '0':
dp[i] = dp[i-1]
if i != 1 and '09' < s[i-2:i] < '27':
dp[i] += dp[i-2]
return dp[-1]
s="226"
print(numDecodings(s))
15.最长公共子串
采用一个二维矩阵来记录中间结果,矩阵的横坐标为字符串1的各个字符,矩阵的纵坐标为字符串2的各个字符。遇到相等字符,则该位置的值加1,最后返回最大值,并记录终止位置。用空间换时间,将时间复杂度由o(n^3)
下降到o(n^2)
def maxCommonSub(str1,str2):
str1_len=len(str1)
str2_len=len(str2)
record=[[0 for _ in range(str2_len+1)] for _ in range(str1_len+1)]
maxlen=0
p=0
for i in range(str1_len):
for j in range(str2_len):
if str1[i]==str2[j]:
record[i+1][j+1]=record[i][j]+1
if record[i+1][j+1]>maxlen:
maxlen=record[i+1][j+1]
p=i+1
return str1[p-maxlen:p],maxlen
str1="abcdef"
str2="jjcdef"
print(maxCommonSub(str1,str2))
16.通过前序和中序遍历还原二叉树, 用递归
def restruct_tree(pre_order, in_order):
if len(pre_order) == 0:
return 0
else:
root = pre_order[0]
depth = in_order.indx(root)
temp = TreeNode(root)
temp.left = restruct_tree(pre_order[1: depth + 1], in_order[: depth])
temp.right = restruct_tree(pre_order[depth + 1:], in_order[depth + 1:])
return temp
17.排序链表
归并排序,
- 找中点,把链表一分为二
- 递归处理左右半边
- 合并排好序的部分
class Solution(object):
def sortList(self, head):
if not head or not head.next:
return head
pre, slow, fast = head, head, head
while fast and fast.next: #找链表中点
pre = slow
slow = slow.next
fast = fast.next.next
pre.next = None
left, right = self.sortList(head), self.sortList(slow)
return self.merge(left, right)
def merge(self, l1, l2):
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
head = ListNode(l1.val)
head.next = self.merge(l1.next, l2)
else:
head = ListNode(l2.val)
head.next = self.merge(l1, l2.next)
return head
18.顺序打印数组
重点是旋转时的索引对应关系
def rotate(arr):
temp=[[0 for _ in range(len(arr))] for _ in range(len(arr[0]))]
for i in range(len(arr[0])):
for j in range(len(arr)):
temp[i][j]=arr[j][len(arr[0])-1-i]
return temp
def getCyclePrint(arr):
result=[]
while len(arr)!=0:
result=result+arr[0]
arr.pop(0)
if len(arr)==0:
break
arr=rotate(arr)
return result
matrix = [[1,2,3],[4,5,6],[7,8,9]]
print(getCyclePrint(matrix))
19.删除链表中重复元素
def deleteDuplicates(head):
cur=head
while cur and cur.next:
if cur.val==cur.next.val:
cur.next=cur.next.next
else:
cur=cur.next
return head
20.二叉树最近公共祖先
class TreeNode:
def __init__(self,val):
self.val=val
self.left,self.right=None,None
def lowestCommon(root,a,b):
if root is None or root==a or root==b:
return root
left=lowestCommon(root.left,a,b)
right=lowestCommon(root.right,a,b)
if left and right:
return root
if not left:
return right
if not right:
return left
return None
21.二叉树中和为某一值的路径
def findpath(root,expectNumber):
ans=[]
if root==None:
return ans
def iterpath(root,expectNumber,dir=[]):
if expectNumber>root.val:
dir.append(root.val)
if root.left!=None:
iterpath(root.left,expectNumber-root.val,dir)
if root.right!=None:
iterpath(root.right,expectNumber-root.val,dir)
elif expectNumber==root.val:
dir.append(root.val)
if root.left==None and root.right==None:
ans.append(dir)
else:
dir.append(0)
dir.pop()
iterpath(root,expectNumber)
return ans
22.二维有序数组中的查找
bool Solution::FindTwoDimention(int * matrix, int rows, int columns, int number)
{
int row_idx =0;
int col_idx = columns - 1;
if (matrix != nullptr && rows > 0 && columns > 0)
{
while (row_idx < rows && col_idx >= 0)
{
int ele = matrix[row_idx*rows + col_idx];
if (ele == number)
return true;
else if (ele > number)
col_idx--;
else
row_idx++;
}
}
return false;
}
23.大数相乘
模拟乘法,手算累加,时间复杂度:o(n^2)
分治,快速乘法,时间复杂度:o(n^log3)
def matmul(num1,num2):
num1.reverse()
num2.reverse()
print('num1',num1)
print('num2',num2)
num3=[0 for _ in range(len(num1)+len(num2))]
for i in range(len(num1)):
for j in range(len(num2)):
num3[i+j]+=num1[i]*num2[j]
print('num3',num3)
for k in range(len(num3)):
if num3[k]>9:
num3[k+1]=num3[k]/10
num3[k]=num3[k]%10
num3.reverse()
return num3