2021-2-19 构建字典序最大的可行序列 二叉树的右视图

题目1 构建字典序最大的可行序列

给你一个整数 n ,请你找到满足下面条件的一个序列:

整数 1 在序列中只出现一次。
2 到 n 之间每个整数都恰好出现两次。
对于每个 2 到 n 之间的整数 i ,两个 i 之间出现的距离恰好为 i 。
序列里面两个数 a[i] 和 a[j] 之间的 距离 ,我们定义为它们下标绝对值之差 |j - i| 。

请你返回满足上述条件中 字典序最大 的序列。题目保证在给定限制条件下,一定存在解。

一个序列 a 被认为比序列 b (两者长度相同)字典序更大的条件是: a 和 b 中第一个不一样的数字处,a 序列的数字比 b 序列的数字大。比方说,[0,1,9,0] 比 [0,1,5,6] 字典序更大,因为第一个不同的位置是第三个数字,且 9 比 5 大。

示例 1:
输入:n = 3
输出:[3,1,2,3,2]
解释:[2,3,2,1,3] 也是一个可行的序列,但是 [3,1,2,3,2] 是字典序最大的序列。

示例 2:
输入:n = 5
输出:[5,3,1,4,3,5,2,4,2]

本题采用回溯法。顺序填写数组,每个位置由大到小挨个数字进行尝试。
若尝试的数字,一直到最后一个位置都可以填入,则获得字典序最大的可行序列。
另外,设置一个标记数组visit,在某个位置填写数字前,先判断数字是否已填入。

class Solution {
public:
    vector<int> constructDistancedSequence(int n) {
    	//字典序最大序列数组,初始化全部为1,则判断1时无需再重新赋值
        vector<int> vec(2*(n-1)+1 , 1);
        //访问数组,判断数字是否已填入
        vector<bool> visit(n,false);
        //n:数字个数   0:从第0个位置填
        getSolution(n,0,vec,visit);
        return vec;
    }
    
    bool getSolution(int n , int pos , vector<int> &vec , vector<bool> &visit) 
    {
    	//根据题意可以知道,结果数组大小为2*(n-1)+1个,及2*n-1个
    	//填写到头
        if(pos  == 2*n-1) return true;
        //该位置已填写,处理下一位置
        if(vec[pos] > 1)
        {
            if(getSolution(n,pos+1,vec,visit))
                return true;
            else return false;
        }
        //该位置仍未填写,从n到1开始尝试填写
        for(int i=n ; i>=1 ; i--)
        {
        	//i已填写过,查看下一个数字
            if(visit[i-1] == true) continue;
            else
            {
            	//若填写数字为1
                if(1 == i)
                {
                	//标记已填入
                    visit[i-1] = true;
                    //递归处理下一个位置
                    if(getSolution(n,pos+1,vec,visit))
                    	//成功一路返回true
                        return true;
                    //失败则撤销标记,尝试填写下一个数字
                    visit[i-1] = false;
                }
                else
                {
                	//pos+i到头不在数组范围内 或 pos+i位置已占,判断下一个数字
                    if((pos+i) >= 2*n-1 || vec[pos+i] > 1) continue;
                    //标记已填入
                    visit[i-1] = true;
                    //数组填入数字
                    vec[pos] = vec[pos+i] = i;
                    //递归处理下一个位置
                    if(getSolution(n,pos+1,vec,visit))
                    	//成功一路返回true
                        return true;
                    //失败则还原数组,撤销标记,尝试填写下一个数字
                    vec[pos] = vec[pos+i] = 1;
                    visit[i-1] = false;
                }
            }
        }
        return false;
    }
};

题目2 二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <—
/
2 3 <—
\
5 4 <—

解1 DFS

通过对树进行根-右-左的顺序的递归遍历,并记录每个遍历的结点的层数。根据遍历的顺序则可知每层最先遍历的即是最右边的结点。

方式1:
可以通过建立一张哈希表,将层数和结点对应起来;
若该层无对应结点,加入数组;
若该层已有结点对应,则跳过

class Solution {
	//hash表建立
     unordered_map<int,int> mapLevToVal;
public:
    vector<int> rightSideView(TreeNode* root) {
    	//创建数组
        vector<int> rView;
        getSolution(root,rView,1);
        return rView;
    }
    void getSolution(TreeNode* root , vector<int> &rView, int level)
    {
        if(root == NULL) return;
        //层数未对应结点
        if(mapLevToVal[level] == 0)
        {
            mapLevToVal[level] = root->val;
            rView.push_back(root->val);
        }
        //递归右
        if(root->right != NULL) getSolution(root->right,rView,level+1);
        //递归左
        if(root->left != NULL) getSolution(root->left,rView,level+1);
    }
};

方式2
可以通过判断数组的大小,老确定某层最有结点是否已经加入数组。
如果层数大于数组的大小,说明该层还未遍历到,添加一个元素到数组后面即可
如果层数小于数组的大小,则说明该层最右结点已遍历,则不需要添加数组。

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> rView;
        getSolution(root,rView,1);
        return rView;
    }
    void getSolution(TreeNode* root , vector<int> &rView, int level)
    {
        if(root == NULL) return;
        //若结果数组空间大小比level小,说明第level层还没存,添加到后面;否则说明已存入,且根据遍历顺序的值肯定是该层最右边的结点
        if(rView.size() == level-1)
            rView.push_back(root->val);
        if(root->right != NULL) getSolution(root->right,rView,level+1);
        if(root->left != NULL) getSolution(root->left,rView,level+1);
    }
};

解2 BFS

借助队列,对树进行广度遍历,先将每层结点按照由左至右的顺序入队,处理每一层之前取出队尾元素放入结果数组中即可。

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) 
    {
        queue<TreeNode*> Q;
        vector<int> vec;
        if(root == NULL) return vec;
        //根节点入队
        Q.push(root);
        while(!Q.empty())
        {
        	//获取当前层结点个数
            int size = Q.size();
            //取出本层的队尾,加入结果数组
            vec.push_back(Q.back()->val);
            while(size > 0)
            {
            	//将该层所有结点的左右孩子再依次入队,并将本层结点抛出
                TreeNode* pNode = Q.front();
                Q.pop();
                if(pNode->left != NULL) Q.push(pNode->left);
                if(pNode->right != NULL) Q.push(pNode->right);
                size--;
            }
        }
        return vec;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值