zoukankan      html  css  js  c++  java
  • 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
        }
    }
    
  • 相关阅读:
    poj2392 Space Elevator(多重背包问题)
    poj1703 Find them, Catch them(并查集的应用)
    HDU 1867 A + B for you again(KMP算法的应用)
    HDU 1358 Period(kmp简单解决)
    nyoj 460 项链 (区间dp)
    Python内置函数(9)——callable--转载
    Python的hasattr() getattr() setattr() 函数使用方法详解--转载
    python assert 断言详细用法格式
    sam文件格式
    Linux中重定向--转载
  • 原文地址:https://www.cnblogs.com/9527s/p/14680916.html
Copyright © 2011-2022 走看看