题目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;
}
};