目录
lt66 加一
数组加一
func plusOne(digits []int)[]int {
if len(digits)==0{
return []int{}
}
for i:=len(digits)-1;i>=0;i--{
//不等于9则加1返回
if digits[i]!=9{
digits[i]++
return digits
}
//等9则加1后进位
digits[i]=0
}
//最后多一位
res:=make([]int,0)
res = append(res,1)
res = append(res,digits...)
return res
}
480 滑动窗口中位数
- 方法一
维护一个窗口,插入排序,每次更新替换窗口的值,复杂度较高
func medianSlidingWindow(nums []int, k int) []float64 {
//插入排序
res:=[]float64{}
if k>len(nums){
return res
}
win:=make([]int,k)
for i:=0;i<k;i++{
win[i] = nums[i]
for j:=i;j>0;j--{
if win[j]<win[j-1]{
win[j],win[j-1] = win[j-1],win[j]
}else{
break
}
}
}
//最初窗口的值
res = append(res,getMid(win))
for i:=k;i<len(nums);i++{
res =append(res,getMid(window(win,nums[i],nums[i-k])))
}
return res
}
//返回更新后的窗口
func window(arr []int,val, last int)[]int{
i:=0
//窗口中找到要去除的值所在位置
for ;i<len(arr);i++{
if arr[i]==last{
break
}
}
arr[i] = val //替换
//左右一次插入排序
for j:=i;j>0;j--{
if arr[j]<arr[j-1]{
arr[j],arr[j-1] = arr[j-1],arr[j]
}else{
break
}
}
for j:=i;j<len(arr)-1;j++{
if arr[j]>arr[j+1]{
arr[j],arr[j+1] = arr[j+1],arr[j]
}else{
break
}
}
return arr
}
//获取中位数
func getMid(arr []int)float64{
n:=len(arr)
if n%2==1{
return float64(arr[n/2])
}else{
return float64(arr[n/2]+arr[n/2-1])/2.0
}
}
41缺失的第一个正数
- 放置替换法
func firstMissingPositive(nums []int) int {
// 时间O(n) 空间O(1)
//利用原数组,值-1位置与此互换,再找第一个不符合本位置的数
for i:=0;i<len(nums);i++{
for nums[i]>0&&nums[i]<=len(nums)&&nums[i] !=nums[nums[i]-1]{
nums[nums[i]-1], nums[i] =nums[i], nums[nums[i]-1]
}
}
for i:=0;i<len(nums);i++{
if nums[i]!=i+1{
return i+1
}
}
return len(nums)+1
}
354 俄罗斯套娃信封
- 传统dp
func maxEnvelopes(envelopes [][]int) int {
if len(envelopes)==0{
return 0
}
n:=len(envelopes)
res:=0
//便捷排序
sort.Slice(envelopes,func(i,j int)bool{
x,y:=envelopes[i],envelopes[j]
return x[0]<y[0]||(x[0]==y[0]&&x[1]>y[1])
})
dp:=make([]int,n) //到i位置最长上升子序列长度
for i:=0;i<n;i++{
dp[i] = 1
}
for i:=1;i<n;i++{
for j:=0;j<i;j++{ //j不超过i
if envelopes[j][1]<envelopes[i][1]{
dp[i] = max(dp[i],dp[j]+1)
}
}
}
for i:=0;i<n;i++{
res = max(res,dp[i])
}
return res
}
func max(x,y int)int{
if x>y{
return x
}else{
return y
}
}
- 二分法
315 计算右侧小于当前元素的个数
- 树状数组
树状数组参考
var a,c[]int //a是离散化后的有序数组 c是树状数组
func countSmaller(nums []int) []int {
//树状数组
if len(nums)==0{
return []int{}
}
// 初始化离散数组
Initcount(nums)
res:=make([]int,0)
c = make([]int,len(nums))
for i:=len(nums)-1;i>=0;i--{
id:=find(nums[i])
res = append(res,getSum(id-1))
update(id) //非下标更新
}
//转换方向
for i:=0;i<len(res)/2;i++{
res[i],res[len(res)-i-1] = res[len(res)-i-1],res[i]
}
return res
}
func lowBit(x int)int{
return x&(-x) //找到x右侧第一个1位置0个数
}
//更新相关的数据,从子到父
func update(pos int){
for pos<len(c){
c[pos]++
pos+=lowBit(pos)
}
}
//计算下标前缀和
func getSum(i int)int{
res:=0
for i>0{
res+=c[i]
i-=lowBit(i)
}
return res
}
//初始化离散有序数组
func Initcount(nums []int){
hash:=map[int]struct{}{}
for _,v:=range nums{
hash[v] = struct{}{}
}
//初始化a,避免上次测试数据影响
a = make([]int,0)
for v:=range hash{
a = append(a,v)
}
sort.Ints(a)
}
//二分查找元素所在下标 ?此处下标+1
func find(x int)int{
return sort.SearchInts(a,x)+1
}
- 归并
493 翻转对
- 树状数组 时间O(NlogN) 空间O(N)
var a,tree []int //a 为离散化后的数据,tree为树状数组
func reversePairs(nums []int) int {
if len(nums)==0{
return 0
}
Initcount(nums)
value:=make(map[int]int,0) //存储下标
for i:=0;i<len(a);i++{
value[a[i]] = i+1
}
//初始化tree
tree = make([]int,len(a)+1) //容量+1
res:=0
right:=len(a)
for i:=0;i<len(nums);i++{
left:=value[nums[i]*2]
res+=getSum(right)-getSum(left) //所有和-小于等于nums[i]*2的,得到大于nums*2的数量
update(value[nums[i]])
}
return res
}
func lowBit(x int)int{
return x&(-x) //找到x右侧第一个1位置0个数
}
//更新相关的数据,从子到父
func update(pos int){
for pos<len(tree){
tree[pos]++
pos+=lowBit(pos)
}
}
//计算下标前缀和
func getSum(i int)int{
res:=0
for i>0{
res+=tree[i]
i-=lowBit(i)
}
return res
}
//初始化离散有序数组
func Initcount(nums []int){
hash:=make(map[int]int,0)
for _,v:=range nums{
hash[v] = 1
hash[v*2] = 1
}
//初始化a
a = make([]int,0)
for v:=range hash{
a = append(a,v)
}
sort.Ints(a)
}
- 归并 时间O(NlogN) 空间O(N)
224基本计算器
- 普通方法,因为只有+ - ( )相对简单
func calculate(s string) int {
//只有+-()
res:=0
op:=1 //符号
num:=0 //计算数值
stack:=make([]int,0)//放符号
stack = append(stack,1)
for i:=0;i<len(s);i++{
if s[i]==' '{ //空格也可以跳过
continue
}
if s[i]>='0'&&s[i]<='9'{
num = num*10+int(s[i]-'0')
continue
}
//增加数值,重置num
res = res+ op*num
num = 0
if s[i]=='+'{
op = stack[len(stack)-1]
}else if s[i]=='-'{
op = -stack[len(stack)-1]
}else if s[i]=='('{
stack = append(stack,op)
}else if s[i]==')'{
stack =stack[:len(stack)-1]
}
}
//最后一个跳过了
res = res+op*num
return res
}
135分发糖果
- 贪心 O(n)O(n)
可以优化空间为O(1)
func candy(ratings []int) int {
if len(ratings)==0{
return 0
}
res:=0
nums:=make([]int,len(ratings))
for i:=0;i<len(ratings);i++{ //从左到右边走一遍
nums[i]=1
if i==0{
continue
}
if ratings[i]>ratings[i-1]{
nums[i] = nums[i-1]+1
}
}
//左侧基础找到最大值
for i:=len(nums)-2;i>=0;i--{
if ratings[i]>ratings[i+1]{
nums[i] = max(nums[i],nums[i+1]+1)
}
res+=nums[i]
}
for i:=0;i<len(nums);i++{
res+=nums[i]
}
return res
}
func max(x,y int)int{
if x>y{
return x
}else{
return y
}
}
887鸡蛋掉落
- dp+二分
func superEggDrop(k int, n int) int {
//dp+二分
dp:=make([][]int,k+1)
for i:=0;i<=k;i++{
dp[i] = make([]int,n+1)
}
//初始化特殊base
//1个鸡蛋 i层楼
for i:=1;i<=n;i++{
dp[1][i] = i
}
//1层楼 i鸡蛋
for i:=1;i<=k;i++{
dp[i][1] = 1
}
//循环 1的情况已经确定
for i:=2;i<=k;i++{
for j:=2;j<=n;j++{
// 非二分,直接每层尝试 找到最小值 复杂度kn^2超时
// tmp:=math.MaxInt32
// for m:=1;m<=j;m++{
// tmp=min(tmp,max(dp[i-1][m-1],dp[i][j-m])) //碎了下一层,不碎上面的
// }
// dp[i][j] = 1+tmp
//二分法
left,right:=1,j
for left+1<right{ //两者距离小于等于1
mid:=(left+right)/2
down:=dp[i-1][mid-1] //碎了 单增
up:=dp[i][j-mid] //没碎 单减
if up>down{
left = mid
}else if up<down{
right = mid
}else{
left = mid
right = mid
}
}
//相差小于等于1的值
leftVal:=max(dp[i-1][left-1],dp[i][j-left])
rightVal:=max(dp[i-1][right-1],dp[i][j-right])
dp[i][j] = 1+min(leftVal,rightVal) //最大值中最小
}
}
return dp[k][n]
}
func min(x,y int)int{
if x>y{
return y
}else{
return x
}
}
func max(x ,y int)int{
if x>y{
return x
}else{
return y
}
}
32最长有效括号
- dp方式 时空O(n)
func longestValidParentheses(s string) int {
//dp 主要研究s[i]==')'的case
if len(s)==0{
return 0
}
dp:=make([]int,len(s)) //dp[i] 代表i结尾有效括号长度
dp[0] = 0
res:=0
for i:=1;i<len(s);i++{
//s[i]=='(' 直接等0 默认忽略
if s[i]==')'{
if s[i-1]=='('{
dp[i] = 2
if i-2>=0{ //考虑 ()() 情况
dp[i] +=dp[i-2]
}
}else if dp[i-1]>0{ //如果()} dp[i-1]<=0 不包含
if i-dp[i-1]-1>=0&&s[i-dp[i-1]-1]=='('{ //(()) 情况
dp[i] = dp[i-1]+2
if i-dp[i-1]-2>=0{ // 考虑 ()(()) 情况 左侧()要考虑
dp[i]+=dp[i-dp[i-1]-2]
}
}
}
}
res=max(res,dp[i])
}
return res
}
func max(x,y int)int{
if x>y{
return x
}else{
return y
}
}
- 使用栈存下标 时空O(n)
func longestValidParentheses(s string) int {
//用栈的方式,栈中存放下标,开始存放-1
stack:=[]int{-1}
res:=0
tmp:=0
for i:=0;i<len(s);i++{
if s[i]=='('{ //直接放下标
stack = append(stack,i)
}else{
//出栈表示匹配,如果栈空则放入下标表示无效的最后一个位置
stack = stack[:len(stack)-1]
if len(stack)==0{ //栈空放右边下标
stack = append(stack,i)
}
tmp = i-stack[len(stack)-1] //不管是否空,减去栈顶存储坐标 初始为) 则去掉-1,放入0,tmp=0-0
}
res = max(res,tmp)
}
return res
}
func max(x,y int)int{
if x>y{
return x
}else{
return y
}
}
- 最优解 时间O(n) 空间O(1)
440 字典序的第k小数字
- 找规律
func findKthNumber(n int, k int) int {
pre,index := 1,1 //1开头 第1个
for index<k{ //不到第k个继续进行计算
count:=getSum(pre,n) //个数
if index+count>k{
pre = pre*10 //进入下一层位置,
index++ //只增加一个
}else if index+count<=k{//当前在范围内
pre++ //切换下一个数字
index += count //第几个index增加
}
}
return pre
}
//计算同层此位置和下一个位置之间差
func getSum(index int,n int)int{ //测试例子 10 3 得到getSum(1)=1 getSum(1)=2
res:=0
for a,b:=index,index+1;a<=n;a,b = a*10,b*10{
res+=min(n+1,b)-a
}
return res
}
func min(x,y int)int{
if x>y{
return y
}else{
return x
}
}