hard相关记录

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
    }
}
posted @ 2021-04-20 14:28  海拉尔  阅读(26)  评论(0编辑  收藏  举报