构造数组的MaxTree

【题目】

对于一个没有重复元素的整数数组,请用其中元素构造一棵MaxTree,MaxTree定义为一棵二叉树,其中的节点与数组元素一一对应,同时对于MaxTree的每棵子树,它的根的元素值为子树的最大值。现有一建树方法,对于数组中的每个元素,其在树中的父亲为数组中它左边比它大的第一个数和右边比它大的第一个数中更小的一个。若两边都不存在比它大的数,那么它就是树根。请设计O(n)的算法实现这个方法。

给定一个无重复元素的数组A和它的大小n,请返回一个数组,其中每个元素为原数组中对应位置元素在树中的父亲节点的编号,若为根则值为-1。

测试样例:
[3,1,4,2],4
返回:[2,0,-1,2]

代码如下:

class MaxTree {
public:
    vector<int> buildMaxTree(vector<int> A, int n) {
    	assert((int)A.size() == n && n >= 0);
        vector<int> res(A.size(), -1);
        stack<int> st;
	for(int i=0; i<A.size(); ++i){
            while(!st.empty() && A[st.top()] < A[i]){
                if(res[st.top()] == -1 || A[res[st.top()]] > A[i])//之前没有大于它的 或者 左边有但我们要选择一个小的父亲
                    res[st.top()] = i;
                st.pop();
            }
            if(!st.empty())
               	res[i] = st.top();
            st.push(i);
        }
        return res;
    }
};

这道题核心在于栈,一种解法是从左往右使用栈遍历一遍数组,统计每个数左边第一个比它大的值,再从右往左遍历一遍,统计每个比它小的值,然后两个值较小的那个就是父亲节点。


但是我采用的是只遍历一遍的方法,使用栈来保存父节点下标。

举例:【3,1,4,2】

首先初始化res为-1,这是有用的。从左向右遍历,第一次为空,0入栈。仅执行st.push(0),它左边没有比它大的数,此时res[0]仍为-1。

继续,A[1] = 1,由于栈不空,且由栈顶保存下标A[st.top()]=A[0]>A[1]=1,所以1入栈,res[1]=0。

继续,A[2]=4,栈不空,且A[2]>A[st.top()]=A[1]=1,所以进入循环。循环中如果栈顶下标所对应元素值比4小,都弹出。如果找到一个res[st.top()]==-1的点,由于是栈结构,只会和该元素位置前的元素比较过,说明该点目前并没有找到任何一个左边比它大的点,所以将该点的res[st.top()]直接赋为i,成为它的父节点。另外一种可能是,由于是栈结构,栈顶只可能之前选择了一个比它大的点是左边比它大的点,所以如果满足A[res[st.top()]]>A[i],说明当前点是左右第一个比它大的点较小的一个,我们选择当前点作为父节点,所以也要更新res[st.top()]=i。

继续循环,就会得出结果。


思路整体:

        // 循环处理每一个元素
        // 需要一个额外的栈来辅助获取两个阶段的最大值(两个阶段指左边最大值和右边最大值)
        // 每次判断一个元素分三种情况
        //  1. 栈为空,也就是初始状态,直接将元素下标入栈(此时该元素的父结点下标为默认值 -1)
        //  2. 栈不为空,同时即将进栈的元素比栈顶元素小,那么直接将元素进栈同时更新当前元素的
        //     父结点下标为i(设定父结点为左边第一个比该元素大的,右侧第一个比该元素大的第3步说明)
        //  3. 栈不为空,同时即将进栈的元素比栈顶元素小,那么需要将栈顶元素出栈,然后比较
        //     需要分情况:
        //     1) 栈顶元素对应父结点下标为null, 说明栈顶元素左侧没有最大值,此时需要更新
        //        栈顶元素对应父结点下标为当前进栈元素的下标 i,然后将栈顶元素pop 出栈
        //     2) 栈顶元素对应的父结点下标对应数组中元素比,i 位置对应数组元素大,由maxTree 的
        //        定义,我们必须保存左侧和右侧相对较小的那个作为最终结果,所以也更新元素下标为i
        //        然后将栈顶元素 pop 出栈
        //     3) 如果不在上面两种情况范围内,直接将栈顶元素出栈,然后继续循环执行 3 步骤


<think>好的,我需要回答用户关于如何使用C#中的Enumerable来构造数组的问题。首先,用户提到了LINQ和Enumerable,所以应该从System.Linq命名空间下的Enumerable类入手。 用户提供的引用材料中,引用[1]和引用[2]都提到了使用Enumerable.Range来生成数组的例子。比如,引用[1]中的代码是int[] numbers = Enumerable.Range(1, 100).ToArray();,这说明Enumerable.Range是一个常用的方法,可以生成连续整数序列,并通过ToArray转换为数组。我应该先介绍这个方法,给出示例代码。 接下来,除了Range,Enumerable还有其他方法,比如Repeat,用来生成重复元素的数组。例如,Enumerable.Repeat("hello", 5)会生成包含五个"hello"的序列,然后ToArray转为数组。这部分也需要提及,展示不同的构造方式。 然后,可能需要更复杂的数组构造,比如生成随机数或者特定模式的序列。这时候可以结合Select方法,比如使用Enumerable.Range生成索引,然后用Select转换每个元素。例如,生成1到10的平方数数组:numbers.Select(n => n * n).ToArray()。这里可以举一个例子,说明如何结合Linq方法灵活构造数组。 另外,用户可能需要了解如何生成空数组或单元素数组。Enumerable.Empty<int>()可以生成空序列,再转换为数组。还有,对于单个元素,可以用Enumerable.Repeat(value, 1),不过直接new[] { value }可能更高效,但这也是一种方法。 需要注意代码示例的正确性,确保语法正确,比如Lambda表达式的写法,ToArray的使用。同时,要符合用户要求的格式,行内数学表达式用$...$,但这里可能用不上。需要检查是否有需要格式化的数学内容,不过这个问题主要涉及代码,可能不需要数学表达式。 最后,根据用户提供的示例回答结构,需要在回答后生成相关问题。问题可以涉及性能优化、不同方法之间的区别,或者更高级的构造方法,比如生成斐波那契数列或其他复杂结构。 总结步骤: 1. 介绍Enumerable.Range并给出示例。 2. 介绍Enumerable.Repeat。 3. 展示结合Select生成复杂数组。 4. 提到Empty和单元素数组的生成。 5. 提供相关问题。</think>### 使用 Enumerable 构造数组的 C# LINQ 示例 在 C# 中,`Enumerable` 类(位于 `System.Linq` 命名空间)提供了多种静态方法用于生成序列数据。结合 `ToArray()` 方法,可以轻松构造数组。以下是具体实现方法: --- #### 1. **生成连续整数数组** 使用 `Enumerable.Range(int start, int count)` 生成连续整数序列,再通过 `ToArray()` 转换为数组: ```csharp using System; using System.Linq; class Program { static void Main() { // 生成 1 到 100 的整数数组 int[] numbers = Enumerable.Range(1, 100).ToArray(); Console.WriteLine($"数组长度: {numbers.Length}, 第一个元素: {numbers[0]}"); } } ``` --- #### 2. **生成重复元素的数组** 使用 `Enumerable.Repeat<T>(T element, int count)` 生成重复元素的序列: ```csharp // 生成包含 5 个 "hello" 的字符串数组 string[] greetings = Enumerable.Repeat("hello", 5).ToArray(); Console.WriteLine(string.Join(", ", greetings)); // 输出: hello, hello, hello, hello, hello ``` --- #### 3. **生成复杂模式的数组** 结合 `Select` 方法实现自定义逻辑,例如生成平方数序列: ```csharp // 生成 1 到 10 的平方数数组 int[] squares = Enumerable.Range(1, 10) .Select(n => n * n) .ToArray(); Console.WriteLine(string.Join(" ", squares)); // 输出: 1 4 9 16 25 36 49 64 81 100 ``` --- #### 4. **生成空数组或单元素数组** - **空数组**: ```csharp int[] emptyArray = Enumerable.Empty<int>().ToArray(); ``` - **单元素数组**: ```csharp int[] singleElement = Enumerable.Repeat(42, 1).ToArray(); ``` --- ### 性能与注意事项 - **延迟执行**:`Enumerable` 方法默认返回 `IEnumerable<T>`,调用 `ToArray()` 会立即执行查询并分配内存[^1]。 - **效率优化**:对大规模数据,建议直接预分配数组长度,避免频繁扩容[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值