leetcode 牛客编程 子序列 树 数组(积累)

牛客和leetcode有很多重复
语言时而c++ 时而go

子序列问题

最长递增子序列II

输出arr的最长递增子序列,如果多个,输出字典序最小的。

  • 二分+dp
    二分找到对应位置,maxLen记录当前位置i结尾的最长子序列值
    后续找最小字典序,从后向前寻找即可。
 vector<int> LIS(vector<int>& arr) {
        // write code here
        if(arr.size()<1) return {};
        vector<int>res; //保留临时结果,单非最终结果
        vector<int>maxLen;  //存放以i处数字结尾的最长子序列长度
        res.push_back(arr[0]);
        maxLen.push_back(1);
        for (int i=1;i<arr.size();i++)
        {
            if(arr[i]>res.back())//大于则放入res即可
            {
                res.push_back(arr[i]);
                maxLen.push_back(res.size()); //i处长度增加
            }else{
                //找到大于等于val的元素位置放入
                //不手写二分可使用  int pos = lower_bound(res.begin(),res.end(),arr[i])-res.begin();
               int pos = binary(res,0,res.size()-1,arr[i]);
                res[pos] = arr[i];
                maxLen.push_back(pos+1); //坐标+1为长度
            }
        }
        
        //字典序最小的  
        for(int i=arr.size()-1,j = res.size();j>0;i--)
        {
            if(maxLen[i]==j)//长度为j res位置坐标为j-1
            {
                res[--j] = arr[i];
            }
        }
        return res;
    }
    
    //二分寻找大于等于target位置
    int binary(vector<int> res,int low,int high,int target)
    {
        int mid;
        while(low<=high)
        {
            mid = low+(high-low)/2;
            if(res[mid]>=target)
            {
                if(mid==0||res[mid-1]<target)
                {
                      return mid;
                }
                else{
                    high = mid-1;
                }
            }else{
                low = mid+1;
            }
        }
        return low;
    }
    
最长递增子序列I

求最长递增子序列长度
上面会了,此题秒解,返回res长度即可 ,maxLen不需要

  • 二分
int lengthOfLIS(vector<int>& arr) {
     if(arr.size()<1) return {};
        vector<int>res; //保留临时结果,单非最终结果
        res.push_back(arr[0]);
        for (int i=1;i<arr.size();i++)
        {
            if(arr[i]>res.back())//大于则放入res即可
            {
                res.push_back(arr[i]);
            }else{
                //找到大于等于val的元素位置放入
                //不手写二分可使用  int pos = lower_bound(res.begin(),res.end(),arr[i])-res.begin();
               int pos = binary(res,0,res.size()-1,arr[i]);
                res[pos] = arr[i];
            }
        }
        
       return res.size();
    }
    
    //二分寻找大于等于target位置
    int binary(vector<int> res,int low,int high,int target)
    {
        int mid;
        while(low<=high)
        {
            mid = low+(high-low)/2;
            if(res[mid]>=target)
            {
                if(mid==0||res[mid-1]<target)
                {
                      return mid;
                }
                else{
                    high = mid-1;
                }
            }else{
                low = mid+1;
            }
        }
        return low;
    }

最长递增子序列个数

leetcode673
求最长递增子序列个数

  • 双循环 时间O(n^2)
    dp 为i位置结尾最大子序列(LIS)长度
    count 为i位置最大子序列组合数
 int findNumberOfLIS(vector<int>& nums) {
        int n = nums.size();
        if(n<=0) return 0;
        vector<int>dp(n,1); //i位置结尾的最大子序列
        vector<int>count(n,1);  //i结尾最大子序列的组合个数
        for(int i=1;i<n;i++)
            for (int j = 0;j<i;j++)
            {
                if(nums[i]>nums[j])
                {
                    if(dp[j]+1>dp[i])//第一次遍历到
                    {
                        dp[i] = dp[j]+1;
                        count[i] = count[j];
                    }
                    else if(dp[j]+1==dp[i])//第二次遍历
                    {
                        count[i]+=count[j];
                    }
                }
            }
        int tmp = 0;
        int res = 0;
        for(int i=0;i<n;i++)
        {
            tmp = max(tmp,dp[i]);
        }
        for(int i=0;i<n;i++)
        {
            if(tmp==dp[i])
                res+=count[i];
        }
        return res;
    }
数组最长连续子序列

无序数组反最长连续子序列长度
[100,4,200,1,3,2] 返回4

  • 排序计算
    复杂度应该是排序的O(nlogn)
    排序,后比前面大1,count++,全局记录最大值
int MLS(vector<int>& arr) {
        // write code here
        if(arr.empty()) return 0;
        int res =0;
        int count=1;
        //sort即可
        FastThree(arr,0,arr.size()-1);
        //sort(arr.begin(),arr.end());
        for(int i=0;i<arr.size()-1;i++)
        {
            if(arr[i+1]-arr[i]==1)
                count++;
            else if(arr[i+1]==arr[i])
                continue;
            else
                count=1;
            res = max(res,count);
        }
        return res;
    }
    //快排写着玩的
    void Fast(vector<int>&arr,int low,int high){
      
        if(low>high)return ;
        int start = low;
        int end = high;
        int tmp = arr[low];
        while(start<end)
        {
            while(start<end&&arr[end]>=tmp) end--;
            arr[start] = arr[end];
            while(start<end&&arr[start]<=tmp) start++;
            arr[end] = arr[start];
        }
        arr[start] = tmp;
        Fast(arr, low, start-1);
        Fast(arr,start+1,high);
    }
    
    //三路快排熟悉一下,因为有重复元素 注意边界值
    void  FastThree(vector<int>&arr,int low ,int high)
    {
        if(low>=high)return ;
        int tmp = arr[low];
        int i=low;
        int j=low;
        int k = high;
        while(i<=k)
        {
            if (arr[i]<tmp) swap(arr[i++], arr[j++]);
            else if(arr[i]>tmp) swap(arr[i],arr[k--]);
            else i++;
        }
        FastThree(arr,low,j);
        FastThree(arr,k+1,high);
    }
  • set去重排序
    时空O(n)

 int MLS(vector<int>& arr) {
        if(arr.empty())return 0;
        int res =0;
        set<int>hash;
        for(int i=0;i<arr.size();i++)
            hash.insert(arr[i]);
        set<int>::iterator it;
        int num = 0;
        
        for(it = hash.begin();it!=hash.end();it++)
        {
            //包含比当前小1,则计算过,跳过
            if(hash.count(*it-1))continue;
            
            int end = *it; //记录值
            while(hash.count(end+1)) //有比当前+1的,一直找到最后
                end++;
            
            res = max(res,end-*it+1);//保留最大值
            
        }
        return res;
    }
  • 并查集
    待完善

树相关

恢复二叉搜索树
  • 法一

中序遍历保留每个节点,排序后重新赋值 空间O(n)

var res []int
var list [] *TreeNode
func recoverTree(root *TreeNode)  {
	//记得初始化
		res = make([]int,0)
		list = make([]*TreeNode,0)
		dfs(root)
		sort.Ints(res)
		for i:=0;i<len(res);i++{
			list[i].Val = res[i]
		}
}

//中序遍历
func dfs (root *TreeNode) {
	if root==nil{
		return
	}
	dfs(root.Left)
	res = append(res,root.Val)
	list = append(list,root)
	dfs(root.Right)
}

  • 法二 不用全部排序,找到前面和后面的交换位置 空间仍然是O(N)

  • 法三
    Morris遍历 空间O(1)

判断二叉搜索树,平衡树
  • 二叉搜索树
    中序为顺序,小于上一个不符合
 //c++
 long pre  = LONG_MIN;
    bool isValidBST(TreeNode* root) {
        if(root==NULL)
        return true;
        if(!isValidBST(root->left))//左子数非真
        return false;
        if(root->val<=pre)//中序,当前要大于等于之前
         return false;
        pre =root->val;//记录上一个
        return isValidBST(root->right);

    }
  • 平衡树
bool flag = true;
    bool IsBalanced_Solution(TreeNode* pRoot) {
         dfs(pRoot);
        return flag;
        
    }
    int dfs(TreeNode*root)
    {
        if(!root)
            return 0;
        int left = dfs(root->left);
        int right = dfs(root->right);
        
        if(abs(left-right)>1)
        {
            flag = false;
        }
        return right>left?right+1:left+1;
    }
判断镜像
   bool isSymmetric(TreeNode* root) {
        if(root==NULL)
            return true;
        return equal(root->left, root->right);
    }
    
    bool equal(TreeNode*left,TreeNode*right)
    {
        if(left==NULL&&right==NULL)
            return true;
        if(left==NULL||right==NULL)
            return false;
        if(left->val!=right->val)
            return false;
            //左子树右==右子树左,左子树左==右子树右
        return equal(left->left,right->right)&&equal(left->right,right->left);
    }
序列化二叉树

每个value以!结尾,空用#表示
牛客和leetcode有略微不同,牛客是char*需要和string进行转换方便写题

 char* Serialize(TreeNode *root) {  
        string res;
        queue<TreeNode*>que; //队列放置
        que.push(root);
        while(!que.empty())
        {
            TreeNode*tmp = que.front();
            que.pop();
            if(tmp==NULL) //NULL跳过
            {
                res.push_back('#');
                res.push_back('!');
                continue;
            }
            res+=to_string(tmp->val);
            res.push_back('!');
            que.push(tmp->left);
            que.push(tmp->right);
        }
        res.pop_back();//去除最后一个!
        char *str = new char[res.length()+1]; //长度+1
        strcpy(str, res.c_str());
        return str;
    }
    
    TreeNode* Deserialize(char *str) {
         if(str==NULL)return NULL;
         string ret(str);
        if(ret.size()==0||ret[0]=='#')
            return NULL;
        
        vector<TreeNode*>res;
        int i=0;
        while(i<ret.size())
        {
           string tmp = "";
           //!为分割
            while(i<ret.size()&&ret[i]!='!')
            {
                tmp.push_back(ret[i]);
                i++;
            }
            if(tmp=="#")
            {
                 TreeNode*node = NULL;
                 res.push_back(node);   
            }
            else{
                TreeNode*node = new TreeNode(NULL);
                node->val = stoi(tmp);
                res.push_back(node);
            }
            i++;
        }
        //转换为二叉树形式 
        int j = 1;
        for(int i=0;j<res.size();i++)
        {
            if(!res[i])
                continue;
            if(i<res.size())
            {
                res[i]->left = res[j];
                j++;
            }
            if(i<res.size())
            {
                res[i]->right =res[j];
                j++;
            }
        }
        return res[0];
    }
前中,中后构建二叉树

重点是对于边界值的判断

  • 已知前序中序
func buildTree(preorder []int, inorder []int) *TreeNode {
	n:=len(preorder)
	if n==0{
		return nil
	}
	return dfs(preorder,inorder,0,n-1,0,n-1)
}

func dfs(preorder []int, inorder []int,preleft,preright ,inoleft,inoright int)*TreeNode{
	if preleft>preright||inoleft>inoright{
		return nil
	}
	pos:= 0 //中序位置
	for i:=inoleft;i<=inoright;i++{
		if inorder[i]==preorder[preleft]{
			pos = i
			break
		}
	}
	//左边长度
	length:=pos-inoleft
	root:=new(TreeNode)
	root.Val = preorder[preleft]
	root.Left = dfs(preorder,inorder,preleft+1,preleft+length,inoleft,pos-1)
	root.Right = dfs(preorder,inorder,preleft+1+length,preright,pos+1,inoright)
	return root
}
  • 已知中序后续
func buildTree(inorder []int, postorder []int) *TreeNode {
	n:=len(inorder)
	if n==0{
		return nil
	}
	return dfs(inorder,postorder,0,n-1,0,n-1)
}

func dfs(inorder []int,postorder []int,inst,inen,post,poen int) *TreeNode {
	if inst>inen||post>poen{
		return nil
	}
	root:=new(TreeNode)
	root.Val = postorder[poen]

	//寻找中序位置
	pos:=0
	for i:=inst;i<=inen;i++{
		if inorder[i]==postorder[poen]{
			pos = i
			break
		}
	}
	//右半部分长度
	length:=inen-pos
	root.Left = dfs(inorder,postorder,inst,pos-1,post,poen-length-1)
	root.Right = dfs(inorder,postorder,pos+1,inen,poen-length,poen-1)
	return root
}
前中后序非递归遍历

开始不要放入

  • 前序
func preorderTraversal(root *TreeNode) []int {
	var res []int
	rt:=root
	var stack []*TreeNode
	//开始不装入
	for len(stack)!=0||rt!=nil{
		for rt!=nil{
			res = append(res,rt.Val)
			stack = append(stack,rt)
			rt = rt.Left
		}

		if len(stack)!=0{
			tmp:=stack[len(stack)-1]
			stack = stack[:len(stack)-1]
			rt = tmp.Right
		}
	}
	return res
}
  • 中序
    和前序类似,在下面装入
func inorderTraversal(root *TreeNode) []int {
	res:=make([]int,0)
	stack:=make([]*TreeNode,0)
	rt:=root
	for len(stack)!=0||rt!=nil{
		for rt!=nil{
			stack = append(stack,rt)
			rt = rt.Left
		}

		tmp:=stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		//记录数据放在这里
		res = append(res,tmp.Val)
		rt = tmp.Right
	}
	return res
}
  • 后序
    map记录是否访问,或者判断右子树是否访问过
func postorderTraversal(root *TreeNode) []int {
	res := make([]int,0)
	//记录访问过的节点
	hash:=make(map[*TreeNode]bool)
	stack:=make([]*TreeNode,0)
	rt:=root
	for len(stack)!=0||rt!=nil{
		for rt!=nil{
			stack = append(stack,rt)
			rt = rt.Left
		}
		//取出栈顶元素
		tmp:=stack[len(stack)-1]
		if tmp!=nil&&hash[tmp]{
			//用过则加入结果,去除栈顶元素
			stack = stack[:len(stack)-1]
			res = append(res,tmp.Val)
		}else{
			//没用过,记录下,向右
			hash[tmp] = true
			rt = tmp.Right
		}
	}
	return res
}
之字型遍历二叉树
  • 递归,巧妙,每一层一个数组保存数据
var res [][]int //全局变量
func zigzagLevelOrder(root *TreeNode) [][]int {
    //dfs
    res = make([][]int,0)
    if root==nil{
        return res
    }
    dfs(root,0)
    return res
}
func dfs(root *TreeNode,deepth int){
     if root==nil{
         return 
     }
     if deepth>=len(res){ //进入1层,增加相应的[]int
         res  = append(res,[]int{})
     }
     //0开始偶数鞥正常顺序
     if deepth&1==0{
         res[deepth] = append(res[deepth],root.Val)
     }
     if deepth&1==1{ //奇数层逆序
         res[deepth] = append([]int{root.Val},res[deepth]...)
     }
     dfs(root.Left,deepth+1)
     dfs(root.Right,deepth+1)
}

  • 迭代,两个队列,第二次从右向左
func zigzagLevelOrder(root *TreeNode) [][]int {
    //双队列
    if root==nil{
        return [][]int{}
    }
    res:=make([][]int,0)
    stack1:=make([]*TreeNode,0)
    stack2:=make([]*TreeNode,0)
    stack1 = append(stack1,root)
    for len(stack1)!=0||len(stack2)!=0{
        ret:=make([]int,0)
        size:=len(stack1)
        for i:=0;i<size;i++{
            tmp :=stack1[0]
            stack1 = stack1[1:]
            ret = append(ret,tmp.Val)
            if tmp.Left!=nil{
                stack2 = append(stack2,tmp.Left)
            }
            if tmp.Right!=nil{
                stack2 = append(stack2,tmp.Right)
            }
        }
        if len(ret)!=0{
            res =  append(res,ret)
        }
       
        //右向左
        size = len(stack2)
        ret = make([]int,0)
        for i:=size-1;i>=0;i--{
            tmp:=stack2[len(stack2)-1]
            stack2 = stack2[:len(stack2)-1]
            ret = append(ret,tmp.Val)
            if tmp.Right!=nil{
                stack1 = append([]*TreeNode{tmp.Right},stack1...)
            }
            if tmp.Left!=nil{
                stack1 = append([]*TreeNode{tmp.Left},stack1...)
            }
        }
         if len(ret)!=0{
            res =  append(res,ret)
        }
    }
    return res
}
N叉树层序遍历

bfs放入队列,每次队列长度循环,每个节点的子节点都放入队列

func levelOrder(root *Node) [][]int {
	var res [][]int
	if root==nil{
		return res
	}
	que:=make([]*Node,0)
	que = append(que,root)
	for len(que)!=0{
		lenght:=len(que)
		tmp:=make([]int,0)
		for i:=0;i<lenght;i++{
            //每次取第一个,因为下面已经去除第一个
			tmp = append(tmp,que[0].Val)
            node:=que[0]
			que = que[1:]
			for j:=0;j<len(node.Children);j++{
				if node.Children[j]!=nil{
					que = append(que,node.Children[j])
				}
			}
		}
		res = append(res,tmp)
	}
	return res

}

数组相关(滑动窗口,二分)

lt56 合并区间

二维数组合并区间,先排序再合并

func merge(intervals [][]int) [][]int {
	//排序合并
	if len(intervals)<=1{
		return intervals
	}
	fast(intervals,0,len(intervals)-1) //手撕快排
	var res [][]int
	//前一个尾部大于后一个头,则合并,合并的尾为两个尾部最大    [1,3],[2,6】  是[1,6]
	for i:=0;i<len(intervals);i++{
		if len(res)==0||intervals[i][0]>res[len(res)-1][1]{
			res = append(res,intervals[i])
		}else{
			res[len(res)-1][1] = max(res[len(res)-1][1],intervals[i][1])
		}
	}
	return res
}

func max(x,y int)int  {
	if x>y{
		return x
	}else{
		return y
	}
}

func fast(arr [][]int,low,high int)  {
	start:=low
	end:=high
	if start>end{
		return
	}
	tmp:=arr[low] //赋值在判断之后
	for start<end{
		for start<end&&arr[end][0]>=tmp[0]{
			end--
		}
		arr[start] = arr[end]
		for start<end&&arr[start][0]<=tmp[0]{
			start++
		}
		arr[end] = arr[start]
	}
	arr[start] = tmp
	fast(arr,low,start-1)
	fast(arr,start+1,high)
}
滑动窗口最大值

leetcode 239 单调栈

func maxSlidingWindow(nums []int, k int) []int {
	res:=make([]int,0)
	que:=make([]int,0)//存储索引值
	for i:=0;i<len(nums);i++{
		if len(que)!=0{
			//超出窗口范围则去除
			if i-que[0]>=k{
				que = que[1:]
			}
			for len(que)!=0&&nums[i]>=nums[que[len(que)-1]]{
				que = que[:len(que)-1]
			}
		}
		que = append(que,i)
		if i+1>=k{
			res = append(res,nums[que[0]])
		}
	}
	return res
}
子数组最大累加和 牛客

连续累加最大和
全局记录,和<0则归零

int maxsumofSubarray(vector<int>& arr) {
        if (arr.empty())
            return 0;
        int res = INT_MIN;
        int count = 0;
        for(int i=0;i<int(arr.size());i++)
        {
             count+=arr[i];
             res = max(res,count);
             count = count<0?0:count; //和小于0则归零
        }
        return res;
    }
字符串最长无重复子串长度

[2,2,3,4,3] 为3
set存储从左到右

int maxLength(vector<int>& arr) {
        int n = arr.size();
        if(n==0)return 0;
        int res = 0;
        set<int>hash; //保存,重复则从前向后去除元素,直到没有重复
        int l = 0;
        int r = 0;
        while(r<n)
        {
            if(!hash.count(arr[r]))
            {
                hash.insert(arr[r]);
                r++;
            }else{
                hash.erase(arr[l]);
                    l++;
            }
            res = max(res,int(hash.size()));
        }
        return res;
    }
le11 盛水最多容器

左右双指针,左右最小的向中间移动,移动时更新最大值

func maxArea(height []int) int {
	if len(height)==0{
		return 0
	}
	res:=0
	l:=0
	r:=len(height)-1
	for l<r{
		tmp:=(r-l)*min(height[l],height[r])
		res = max(res,tmp)
		if height[l]>height[r]{
			r--
		}else{
			l++
		}
	}
	return res
}

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
	}
}
接雨水

多种方法解决

  • 双指针
func trap(height []int) int {
    //每次计算一列
    res:=0
    left,right:=0,len(height)-1
    lmax,rmax:=0,0
    for left<right{
        lmax = max(lmax,height[left]) //每次更新左右的最大值
        rmax = max(rmax,height[right])
        if height[left]<height[right]{ //左边小则计算左边,left向右
            res+=lmax-height[left]
            left++
        }else{
            res+=rmax-height[right]
            right--
        }
    }
    return res
}

func max(x,y int)int{
    if x>y{
        return x
    }else{
        return y
    }
}
  • 单调栈
func trap(height []int) int {
    //和84柱状图最大面积类似,但是是单调递减的栈
    //不需要增加辅助接节点,因为只有一个元素无法接到雨水,右边末端为最小也无发构造凹槽
    // 计算方式为凹槽和两边高度较小的差值为h,两边之间的距离为宽度w,乘积为面积
    stack:=[]int{}
    res:=0
    for i:=0;i<len(height);i++{
        for len(stack)!=0&&height[i]>height[stack[len(stack)-1]]{
            h:=height[stack[len(stack)-1]]
            stack = stack[:len(stack)-1]
            if len(stack)==0{
                break
            }
            l:=stack[len(stack)-1]
            minH:=min(height[i],height[l])-h //高度为两边较小-h
            w:=i-l-1
            res += w*minH
        }
        stack =append(stack,i)
    }
    return res
}


func min(x,y int)int{
    if x>y{
        return y
    }else{
        return x
    }
}

其他

合并两个排序链表(递归)
  • 递归
 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;

        if(l1->val<l2->val)
        {
            l1->next = mergeTwoLists(l1->next,l2);
            return l1;
        }else{
            l2->next = mergeTwoLists(l1,l2->next);
            return l2;
        }
    }

k个排序链表合并

leetcode 23

  • 分治法
    每次合并两个,将结果放入队列尾部,直到队列只剩下一个
    面试遇到说这个不是最优解的,我感觉优先队列和这个复杂度差不多
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists)==0{
		return nil
	}
	//合并放尾部,去除头部两个,直到队列剩余为1
	for len(lists)>1{
		lists = append(lists,merge(lists[0],lists[1]))
		lists = lists[2:]
	}
	return lists[0]

}

//合并两个链表
func merge(one *ListNode ,two *ListNode)*ListNode  {
	dummy:=new(ListNode)
	cur:=dummy
	for one!=nil&&two!=nil{
		if one.Val<two.Val{
			cur.Next = one
			one = one.Next
		}else{
			cur.Next  = two
			two = two.Next
		}
		cur = cur.Next
	}
	if one!=nil{
		cur.Next = one
	}else{
		cur.Next = two
	}
	return dummy.Next
}

  • 优先队列
    手动实现优先队列 我吐了
    虽然标准库有优先队列,还是手动踩坑锻炼下
    调试差点吐了,还是参考下标准库里heap的实现方式吧
func mergeKLists(lists []*ListNode) *ListNode {
	if len(lists)==0{
		return nil
	}

	var  heap []*ListNode
	for i:=0;i<len(lists);i++{
		if lists[i]!=nil{
			heap = push(heap,lists[i])
		}
	}
	sink(heap,0)//形成堆
	dummy:=new(ListNode)
	cur:=dummy
	for len(heap)!=0{
		var tmp *ListNode
		heap,tmp = pop(heap)//取出堆顶

		cur.Next = tmp
		cur = cur.Next
		if tmp.Next!=nil{  //非空放入下一个
			heap = push(heap,tmp.Next)
		}
	}
	return dummy.Next
}

//节点下沉
func sink(arr []*ListNode,start int)  {
	length:=len(arr)-1
	for{
		next:=start*2+1
		if next>length{
			return
		}
		if next+1<=length&&arr[next+1].Val<arr[next].Val{
			next++
		}
		if arr[start].Val<arr[next].Val{
			break
		}
		arr[start],arr[next] = arr[next],arr[start]
		start = next
	}
}

//节点上升只需要找父节点
func swim(arr []*ListNode,start int){
	for {
		parent:=(start-1)/2
		if start==parent||arr[parent].Val<=arr[start].Val{
			break
		}
		arr[parent],arr[start] = arr[start],arr[parent]
		start = parent
	}
}

//insert
func push(arr []*ListNode,root *ListNode)[]*ListNode  {
	//上升节点
	arr = append(arr,root)
	swim(arr,len(arr)-1)
	return arr
}

//取出优先高的,结尾放头部,减少容量,下沉节点
func pop(arr []*ListNode)([]*ListNode,*ListNode)  {
	tmp:=arr[0]
	arr[0] = arr[len(arr)-1]
	arr = arr[:len(arr)-1]
	sink(arr,0)
	return arr,tmp
}

//数组创建链表,方便debug
func Creat(arr []int)*ListNode  {
	root:=new(ListNode)
	cur:=root
	for i:=0;i<len(arr);i++{
		tmp:=new(ListNode)
		tmp.Val = arr[i]
		cur.Next = tmp
		cur = cur.Next
	}
	return root.Next
}

  • 2022.3.30 使用自带的heap实现
func mergeKLists(lists []*ListNode) *ListNode {
    if len(lists)==0{
        return nil
    }
    h:=new(minHeap) //初始化对象,具体使用需要heap.操作
    dummy:=new(ListNode)
    pre:=dummy

    for _,v:=range lists{
        if v!=nil{ //需要判断数组不为空
             heap.Push(h,v)
        }  
    }

    for h.Len()>0{
        tmp:=heap.Pop(h).(*ListNode) //需要断言数据类型
        if tmp.Next!=nil{
            heap.Push(h,tmp.Next)
        }
        pre.Next =tmp
        pre = pre.Next
    }
    return dummy.Next
}


type minHeap []*ListNode

func (h minHeap)Len()int{
    return len(h)
}

func (h minHeap)Less(i,j int)bool{
    return h[i].Val<h[j].Val
}

func (h minHeap)Swap(i,j int){
    h[i],h[j] = h[j],h[i]
}

func (h *minHeap)Push(x interface{}){ //Push和Pop需要加为指针,上面的不需要
    *h = append(*h,x.(*ListNode))
}

func (h *minHeap)Pop()interface{}{ //扔出顶部元素
    x:=(*h)[len(*h)-1]  //注意符号加括号,跟优先级有关系
    *h = (*h)[:len(*h)-1] 
    return x
}
牛客 合并两个有序数组

从后向前,把B放入A中,不开辟新的空间

 void merge(int A[], int m, int B[], int n) {
        int i = m-1,j = n-1,len = m+n-1;
        while(i>=0||j>=0)
        {
            if((i>=0&&A[i]>=B[j])||j<0)
                A[len--]=A[i--];
            else{
                A[len--]=B[j--];
            }
           
        }
    }
lt面试题08.06 汉诺塔问题

n个数字,a移动到c
递归问题 时O(2^n) 空O(1)

func hanota(A []int, B []int, C []int) []int {
	n:=len(A)
	move(n,&A,&B,&C)
	return C
}

func move(n int,a *[]int, b *[]int,c *[]int)  {
	if n<=0{
		return
	}
	//a的n-1个经过c移动到b
	move(n-1,a,c,b)
	//a上层移动到c
	*c = append(*c,(*a)[len(*a)-1])
	*a = (*a)[:len(*a)-1]
	//b上的n-1个经过a移动到c
	move(n-1,b,a,c)
}
leetcode69 x的平方根

二分法和牛顿法

  • 二分法
func mySqrt(x int) int {
	mid:=0
	l:=0
	r:=x
	for l<r{
                //(l+r+1)这是为了防止当l = r - 1时,出现死循环的情况
		mid = (l+r+1)>>1
		if mid*mid<=x{
			l = mid
		}else{
			r = mid-1
		}
	}
	return r
}

  • 牛顿法
    主要是迭代公式x = (x + n/x) / 2
func mySqrt(x int) int {
	res:=x
	for res*res>x{
		res = (res+x/res)/2
	}
	return res
}
posted @ 2021-01-31 11:49  海拉尔  阅读(66)  评论(0编辑  收藏  举报