选择最列表中最大的值
一、
新入元素比原来组中最小的小,那只需要1次操作,就可以找到第k大数字
如果进来的元组比最小的大,要进行台哦正,调整logk
于是时间复杂度是N*o(logk),
二、
单次擦欧总,每次进行排序 N*klogk
滑动窗口最大值
一、优先队列
大顶堆MaxHeap 最上面是最大的元素(删除离开的元素,加入新的元素logk,结果是堆顶元素o(1))
最终时间复杂度是NlogK
二、Queue双关队列o(N*1)
1、前k个元素一次加入
2、新的数字加入维护
时间复杂度 hashmap hashset
有序 treemap treeset
哈希略快二叉搜索树,顺序没有要求就用哈希,有要求二叉搜索树
两数之和
返回两数之和等于target的数的下标
一、x+y = 9 两层循环嵌套o(n^2)
二、y = 9-x
枚举x写一个for循环(o(n)),查询一下9-x是否在set里面存在(o(1)) 因此时间复杂度为o(1)
有效的字母异位词
一、sort 任何一个字符串进来,字符串里的所有字母按照字典进行排序
rat - art tar-art 快排的时间复杂度是nlogn
二、用map来进行计数 {letter:count} 任何里面的字符串将字母放在map里面进行计数
循环o(n) map插入删除o(1) 总共时间复杂度o(n)
def isanagram3(self,s,t):
return sorted(s) == sorted(t)
def isanagram1(self,s,t):
dic1,dic2 = {
},{
}
for item in s:
dic1[item] = dic1.get(item,0) + 1
for item in t:
dic2[item] = dic2.get(item, 0) + 1
return dic1 == dic2
def isanagram2(self,s,t):
dic1,dic2 = [0]*26,[0]*26
for item in s:
dic1[ord(item)-ord('a')] += 1
for item in t:
dic2[ord(item)-ord('a')] += 1
# ord() 函数是chr() 函数(对于8 位的ASCII 字符串)的配对函数
return dic1 == dic2
三数之和
[-1,0,1,2,-1,-4] 0
一、暴力解法 a+b+c = 0 o(n^3)
二、c = -(a+b)将整个数组放在一个set里面,只需要o(1)的操作 o(n^2)
三、sort find
整个数组进行排序[-4,-1,-1,0,1,2]
1、loop 枚举a(o(n)),剩下的数组里面找b和c a+b+c>0 c左移 如果小于0,b右移 --o(n^2)
def threesum(self,nums):
if len(nums) < 3:
return []
nums.sort()
res = set()
for i,v in enumerate(nums[:-2]):
if i >= 1 and v == nums[i-1]:
continue
d = {
}
for x in nums[i+1:]:
if x not in d:
d[-v-x] = 1
else:
res.add((v,-v-x,x))
return map(list,res)
def threesum1(self,nums):
res = []
nums.sort()
for i in xrange(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue
l,r = i+1,len(nums)-1
while l < r:
s = nums[i] + nums[r] + nums[l]
if s < 0 :l += 1
elif s > 0: r -= 1
else:
res.append((nums[i],nums[l],nums[r]))
while l <r and nums[l] == nums[l+1]:
l += 1
while l < r and nums[r] == nums[r-1]:
r -= 1
l += 1 ;r -= 1
树&二叉树&二叉搜索树
链表是特殊化的树,树是特殊化的图
class TreeNode:
def __init__(self,val):
self.val = val
self.left,self,right = None ,None
二叉搜索树,也成为有序二叉树,排序二叉树,它可以是一颗空树,或者左子树的所有结点的值小于根节点,右子树的所有结点的值大于根结点
存在本质:让搜索更快,让排列更加有序
验证二叉搜索树
空的树就是一个二叉排序树
一、进行中序遍历
遍历出来的结点组成的数组,升序,结果就是二叉排序树
二、用递归来进行,判断
递归函数,要传min,max函数,再去递归左孩子,得到左孩子的最大值,然后右孩子,找到最小值,判断左边的最大值小于根节点的值,右子树的最小值大于根节点,然后继续递归
def isvalidBST(self,root):
inorder = self.inorder(root)
return inorder == list(sorted(set(inorder)))
def inorder(self,root):
if root is None:
return []
return self.inorder(root.left) + [root.val] + self.inorder(root.right)
def isValidBST(self,root):
self.prev = None
return self.helper(root)
def helper(self,root):
if root is None:
return True
if not self.helper(root.left):
return False
if self.prev and self.prev.val >= root.val
return False
self.prev = root
return self.helper(root.right)
public boolean isValid(TreeNode root,Integer min,Integer max){
if (root=null) return True;
if (min != null && root.val <= min) return false;
if (max != null && root.val >= max) return false;
return isValid(root.left,min,root.val)&&
isvalid(root.right,root.val,max);
}
二叉树/二叉搜索树的最近公共祖先
一、寻找路径path
需要要求有一个父亲指针的问题,但是可以这么想,做不能
从祖先找路径1,路径2,看从根开始,最后一个结点是什么,则变成公共祖先
二、
recursion
find PorQ(root,p,q)以root为根的子树里面,找p和q,找到谁都可以
if root == p or root == q:
return root
findPorQ(root,p,q){
if root == null ||root == p || root == q:
return root
TreeNode left = findPorQ(root.left,p,q)
TreeNode right = findPorQ(root.right,p,q)
return left == null ? right : right == null ? left : root;
}
def lowestcommonancestor(self,root,p,q):
if p.val < root.val > q.val:
return self.lowestcommonancestor(root.left,p,q)
if p.val > root.val < q.val:
return self.lowestcommonancestor(root.right, p, q)
return root
二叉树的遍历(知识)
preorder
inorder
postorder
def preorder(self,root):
if root:
self.traverse_path.append(root.val):
self.preorder(root.left)
self.preorder(root.right)
def inorder(self,root):
if root:
self.preorder(root.left)
self.traverse_path.append(root.val):
self.preorder(root.right)
def postorder(self,root):
if root:
self.preorder(root.left)
self.preorder(root.right)
self.traverse_path.append(root.val):
递归&分治
递归(通过函数体类似进行循环)层层递进,层层回来
def recursion(level,param1,param2,...):
# recursion terminator终止条件
if level > MAX_LEVEL:
print_result
return
# process logic in current level业务逻辑
process_data(level,data...)
# drill down调自己函数本身,解决下一层任务
self.recursion(level +1,p1,...)
#reverse the current level status if needed 进行收尾工作
reverse_state(level)
分治:大问题分成小问题,一一解决
def divide_conquer(problem, param1, param2, ...):
# recursion terminator终止条件
if problem is None:
print_result
return
# prepare data
data = prepare_data(problem)
subproblems = split_problem(problem,data)
# conquer subproblems
subresult1 = self.divide_conquer(subproblems[0],p1,...)
subresult2 = self.divide_conquer(subproblems[1],p1,...)
subresult3 = self.divide_conquer(subproblems[2], p1, ...)
# reverse the current level status if needed 进行收尾工作
result = process_result(subresult1,subresult2,subresult3,...)
计算x的n次方
pow(x,n)
一、直接调库函数 o(1)
二、暴力
写一个循环,每次乘以x,进行求解o(N)
三、让你算x的n次方,能不能让它一份为二,从中间劈开,想n是奇数还是偶数
如果是偶数,n/2刚好是中间,计算y = x ^n/2 result = y * y
如果是奇数,中间x先拿掉,当成偶数来计算,n/2刚好是中间,计算y = x ^n-1/2 result = y * y*x
x^n – x^n/2 – x^n/4 – x^1 or x^0 时间复杂度logN
def myPow(self,x,n):
if not n :
return 1
if n < 0:
return 1/self.myPow(x,-n)
if n % 2:
return x * self.myPow(x,n-1)
return self.myPow(x*x,n/2)
def myPow(self,x,n): # 位运算
if n < 0:
x = 1/x
n = -n
pow = 1
while n:
if n & 1:# 二进制位
pow *= x
x *= x
n >>= 1 # 右移一位
return pow
求众数
并不是任何一个数组都有众数
一、暴力
写两个循环,枚举所有的x,针对每一个x进行计数,返回数值最大的x值(或者大于n/2)最后的时间复杂度是o(N^2)
二、map
{x:count(x)} loop ==> map count o(N)
三、sort[1,2,3,3,3] 重复的次数大于n/2 o(Nlogn)
四、分治
对于数组找左半边找到最大值放入left ,右边也找放入right
如果left == right 那么结果就是他们
如果不相同,比较count(left) count(right) 谁大返回谁 时间复杂度 o(nlogn)
注意:要解决比如出现[1,2,3]的情况
贪心算法
对问题求解,总是旨在当前做最好的选择
位运算
程序中在计算机内存中都是用二进制形式存储
位运算说穿,就是直接对整数在内存中的二进制位进行操作
由于为匀速那直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快
& 与 两个位都为1,结果才为1
| 或 两个位都为0,结果才为0
^ 异或 两个位相同为0,不同为1
_ 取反 0变1,1变0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
》》 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算数右移)有的补0(逻辑右移)
实战常用的位运算操作
x&1 == 1 OR ==0 判断奇偶(x % 2 ==1)
x = x&(x - 1)=> 清零最低位的1 1010000 & 1001111 = 1000000
x & -x => 得到最低为的1 1010000 & 0100000 =
动态规划
1、递归+记忆化 --> 递推
2、状态的定义 opt[n] dp[n] fib[n]
3、状态转移方程 opt[n] = best_of(opt[n-1], opt[n-2], …)
4、最优子结构
动态规划/回溯/贪心
回溯(递归):重复计算
贪心:永远局部最优
DP:记录局部最优子结构/多种记录值