1,排序算法
只要记得哪些排序是不稳定的就可以选对了,记得一句话 “学习真痛苦,“快” “希” “选” 一 “堆” MM 来聊天吧。其中相应的分别是,快速排序、希尔排序、简单选择排序、堆排序,这几个都是不稳定排序,那其他的都是稳定排序了。
1.1 二分查找
int bSearch(int a[], int low, int high, int target){
if(low > high)
return -1;
int mid = low +(high - low)/2;.//防止溢出
if(target<a[mid])
return bSearch(a,low,mid-1,target);
else if(target>a[mid])
return bSearch(a,mid+1,high,target);
//if(target == a[mid])
return mid;
}
http://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html
1.2,选择排序
void SelectionSort(int a [], int n)
{
int min;
//循环n-1次
for(int i = 0 ; i < n-1 ; i++)
{
min = i;
for(int j = i+1; j < n; j++)
{
if(a[j]<a[min])
min = j;
}
swap(a[i],a[min]);
}
}
1.3,冒泡排序
void BubbleSort(int a[], int n)
{
//循环n-1次
for(int i=0; i<n-1; i++)
{
for(int j=0; j<n-i-1; j++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
}
}
}
}
void BubbleSort(int a[], int n)
{
bool exchange;
//循环n-1次
for(int i=0; i<n-1; i++)
{
exchange = false;
for(int j=0; j<n-i-1; j++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
exchange = true;
}
}
if(!exchange)
break;
}
}
1.4,插入排序
void InsertSort(int a[], int n)
{
//从第i=1个元素遍历到最后
for(int i=1; i<n; i++)
{
//将第a[i]插入到前面已排序数组中
int v = a[i];
int j = i-1;
while(j>0&&a[j]>v)
{
a[j+1] = a[j];
j--;
}
a[j] = v;
}
}
1.5,快速排序
int Partition(int a[], int low, int high)
{
int v = a[low];
int i = low;
int j = high+1;
while(true)
{
while(a[++i]<v);
while(a[--j]>v);
if(i<j)
{
swap(a[i],a[j]);
}
else//(i>=j)
{
break;
}
}
swap(a[low],a[j]);
}
void QuickSort(int a[], int low, int high)
{
if(low<high)
{
int pivot = Partition(a,low,high);
QuickSort(a,low,pivot-1);
QuickSort(a,pivot+1,high);
}
}
快速排序的三路划分???
3,搜索算法
3.1 查找唯一重复元素
问题:数组中元素是否唯一
复杂:O(nlog(n))
解法:预排序O(nlog(n))+扫一遍查重O(n)
3.2 查找众数问题
问题:查找数组中出现最频繁元素。
复杂:O(nlog(n))
解法:预排序O(nlog(n))+扫一遍相同元素计数O(n)
3.3 查找过半元素问题
问题:数组中有一个数字出现的次数超过了数组总数的一半,找出这个数字。
出处:《编程之美》2.3 寻找发帖“水王”
复杂:O(n)
解法:
解法一:对所有ID进行排序,再扫描一遍排好序的ID列表,统计各个ID出现的次数,如果某个ID出现的次数超过总数的一半,那么就输出这个ID。时间复杂度为O(N*log2N + N).
解法二:既然已经排好序,而且有某个ID出现的次数超过总数的一半,那么ID列表的中间项一定是这个ID。复杂度为O(1)。
解法三:如果每次删除两个不同的ID(不管是否包含"水王"的ID),那么在剩下的ID列表中,"水王"的ID出现次数肯定仍然超过总数的一半。这样不断重复这个过程,总量就可以降低,从而避免了排序的操作,复杂度为O(N).
代码:
Type Find(Type* ID, int N)
{
Type candidate;
int nTimes, i;
for(i = nTimes = 0; i < N; i++)
{
if(nTimes == 0)
{
candidate = ID[i], nTimes = 1;
}
else
{
if(candidate == ID[i])
nTimes++;
else
nTimes--;
}
}
return candidate;
}
问题扩展1:
数组中有一个数字出现的次数等于或大于了数组长度的一半,找出这个数字。
解答:据题意该数字出现次数一定超过1/3,因此可以从目标数组中去除三个不同的数,随后对剩余的数字进行如题目一的算法, 求出的结果就是我们的目标数字!问题扩展2:
随着Tango的发展,管理员发现,“超级水王”没有了。统计结果表明,有3个发帖很多的ID,他们的发帖数目都超过了帖子总数目N的1/4。你能从发帖ID列表中快速找出他们的ID吗?
解答:参考上面的解法,思路如下:如果每次删除四个不同的ID(不管是否包含发帖数目超过总数1/4的ID),那么,在剩下的ID列表中,原先发帖比例大于1/4的ID所占比例仍然大于1/4。可以通过不断重复这个过程,把ID列表中的ID总数降低(转化为更小的问题),从而得到问题的答案。
void Find(int *ID,int N,int candidate[3])
{
int nTimes[3],i;
nTimes[0]=0;
nTimes[1]=0;
nTimes[2]=0;
candidate[0]=0;
candidate[1]=0;
candidate[2]=0;
for(i=0;i<N;i++)
{
if(candidate[0]==ID[i])
nTimes[0]++;
else if(candidate[1]==ID[i])
nTimes[1]++;
else if(candidate[2]==ID[i])
nTimes[2]++;
else if(nTimes[0]==0)
{
candidate[0]=ID[i];
nTimes[0]=1;
}
else if(nTimes[1]==0)
{
candidate[1]=ID[i];
nTimes[1]=1;
}
else if(nTimes[2]==0)
{
candidate[2]=ID[i];
nTimes[2]=1;
}
else
{
nTimes[0]--;
nTimes[1]--;
nTimes[2]--;
}
}
}
3.4 查找【最小|中值|最大|第k小|前k小】元素
问题:给定一个无序整数数组,返回这个数组中第k小的数。
出处:《算法设计与分析》P142计算中值和选择问题
复杂:O(n)
解法1:【排序+选择】最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn+k)。
解法2:【改进的选择排序】使用选择排序思想,对这个乱序数组按照从大到小选择排序(只进行K次,避免做后N-K个数的排序),总的时间复杂度为O(n*k)。
解法3:【改进的快速排序】使用快速排序思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度为O(nlogk)近似为O(n)。(因为快排的partition操作复杂度O(n))
具体地,将数组按照第一个数字pivot进行划分,将比pivot小的放在左边,比pivot大的放在右边,pivot放中间。返回patition之后pivot的下标j。如果此时j==k(数组下标从1开始)那么说明a[j]就是要找的第k个数。如果j<k,递归查找左半部分;如果j>k,递归查找右半部分。特别地,快速排序的分区法实际上得到了k个最小元素和n-k个最大元素,而不仅仅是第k个元素。
int random_partition(int a[], int l, int u)
{
swap(a, l, randint(l, u));
int i = l;
int j = u+1;
int t = a[l];
while (1) {
do {
i++;
} while (a[i] < t && i <= u);
do {
j--;
} while (a[j] > t);
if (i > j) break;
swap(a, i, j);
}
swap(a, l, j);
return j;
}
int random_select(int a[], int l, int u, int k)
{
assert(l <= u && k>=1 && k <= u-l+1); //确保选择的第k小的数范围不超过数组大小
if (l == u) return a[l]; //如果只有1个元素,可以直接返回
int p = random_partition(a, l, u); //划分
int i = p - l + 1;
if (i == k) //左边数目等于k,返回a[p]
return a[p];
else if (i < k) //左边数目小于k,从右边选择k-i小的元素
return random_select(a, p+1, u, k-i);
else //左边数目大于k,从左边选择第k小的元素
return random_select(a, l, p-1, k);
}
扩展问题1:如果是海量数据,如10G数据,1G内存,求数组中的第k大的数。
复杂:O(nlogk)
解法:哈希Hash(将大文件切割为小文件)+ K容量最小堆 + 多结果合并
其中,维持一个大小为k的小顶堆,遍历一次数组,如果数组中的元素比堆顶的元素大,那么就更新堆。最后堆中存放的是数组中的前k大元素。堆顶元素即为要求的第k大个数。大多数情况下,堆可以全部载入内存。如果K仍然很大,我们可以尝试先找最大的K'个元素,然后找第K'+1个到第2 * K'个元素,如此类推(其中容量K'的堆可以完全载入内存)。不过这样,我们需要扫描所有数据ceil (K/K')次。
扩展问题2:如果是找第k到第m(0<k<=m<=n)大的数呢?
解法:可以用小根堆来先求出m个最大的,然后从中输出k到m个。
3.5 用异或找缺失的数
问题:【连续的数】1到n中缺失了一个数,顺序被打乱,找出缺失的数
复杂:O(n)
解法:
对于丢失一个数的情况:
1)用1+2+...+n减去当前输入数据的总和。时间复杂度:O(n) 空间复杂度:O(1) 【容易溢出】
2)用12...*n除以当前输入数据的总积。时间复杂度:O(n) 空间复杂度:O(1) 【容易溢出】
3)用1^2^...^n的结果再逐个异或当前输入数据。时间复杂度:O(n) 空间复杂度:O(1)
4)对输入数据排序,然后从头到尾遍历一次。时间复杂度O(nlogn) 空间复杂度O(1)
5) 对输入数据进行Hash,然后从头到尾遍历一次。时间复杂度O(n) 空间复杂度O(n)
第三种方法,因为相同的数取异或为0,0^0为0,所以最终按照该方法得到的数就是缺失的那个数。其算法复杂度准确的说为:Theta(2*n-1)。
扩展问题1:【连续的数】1到n中多了一个数,顺序被打乱,找出多的数。
扩展问题2:【不连续的数】给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。
解法1,2:仍可以用异或O(n)算法
扩展问题3:【连续的数】1到n中[缺失了/增加了]两个数,顺序被打乱,找出缺失的数。
扩展问题4:【不连续的数】给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。
解法3,4:假定我们迷失的数字是S1,S2。那么我们全部异或之后得到的就是S1^S2的值。分析一下就可以知道,S1!=S2,也就是说S1^S2!=0; 这样也就是说S1^S2的这个值有二进制位有一位是1,那么我们就可以把这些所有的数字分成2组,一组这个二进制位是1,另一个这个二进制位是0的来重新做异或。这样就可以把其中一个S1求出来了,那再S1^(S1^S2)一下,S2也就得到了。
扩展问题5:【连续的数】1到n之间的n个数不重复乱序,有一个数x变成了y,求这俩数。
扩展问题6:【连续的数】给你n个数,其中有且仅有三个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那三个数。
3.6 查找数组中和为定值的两个数【2sum问题】
问题:能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的数字,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解。
出处:《编程之美》-2.12-快速寻找满足条件的两个数
复杂:O(nlogn)
解法1:【暴力穷举】O(n^2)
解法2:【预排序+二分查找】O(nlogn)
对数组预排序O(NlogN),然后遍历该数组,对每一个数a,都进行查找Sum-a在不在数组中。这种查找在二分查找下需要O(logN),所以综上效率为O(NlogN)+O(N)*O(logN)=O(NlogN).
如下俩个数组:
1、 2、 4、7、11、15 //用15减一下为
14、13、11、8、4、 0 //如果下面出现了和上面一样的数,稍加判断,就能找出这俩个数来了。
第一个数组向右扫描,第二个数组向左扫描。
解法3:【Hash】O(n)
如果在一定的限制条件下,比如说1,数字均为int型,2,此中int型数的范围有一定限制。则可以考虑用hash来获得O(1)的查找效率。方法,首先遍历一遍数组,初始化hash表O(N),然后再次遍历数组,对每一个数字a进行查找SUm-a只需O(1),所以总的效率为:O(N)+O(N)*O(1)=O(N).
解法4:【预排序+对向遍历】O(nlogn)
首先预排序O(NlogN).然后在一个循环体里使用两个循环变量进行反向遍历,并且这两个变量遍历的方向是不变的,从而保证遍历算法的时间复杂度为O(n)。我们先对数组排序,然后再数组的开始和结尾处维护两个游标i,j,然后我们比较arr[i]+arr[j]与sum的大小,如果arr[i]+arr[j]>sum,则i++,如果>sum,则j--,直到找到arr[i]+arr[j]=sum,这样,复杂度即为遍历O(N),排序O(NlogN)。
刚开始一直无法理解这样子一定可以找到这个和么?难道不会漏掉了解得位置。可以这么理解,假如排好序后的数组为1,3,6,a,9,12,17,28,b,35,46 ,那么i最初指向1的位置,j最初指向46的位置,比如所求的是Sum=a+b,a<b,ab在其中数组中某位置上。那么i和j在变化过程中,只考虑i遇到了a或者j遇到了b的时候,必定有一个先遇到,比如i遇到了a,那么这个时候j必定还没指到b,故这是j指到的比b大,从而j减小直到b位置。同理若j先指到了b位置,那么i必定还没指到a(这是我们的前提),然后i现在指到的比a小,故,i增加,直到a位置。
这个是个很奇妙的过程。
//2sum问题,一个未排序数组中找和为sum的所有数对(a,b)
void twoSum(int arr[], int length, int sum){
sort(arr,arr+length);
int i=0;
int j=length-1;
while(i<j){
if(arr[i]+arr[j]==sum){
cout<<arr[i]<<":"<<arr[j]<<endl;
i++;
j--;
}
else if(arr[i]+arr[j]<sum)
i++;
else // arr[i]+arr[j]>sum
j--;
}
}
3.7 查找数组中和为定值的三个数【3sum问题】
扩展问题:如果把这个问题的“两个数字”改为“三个数字”或“任意多的数字”,怎么解?【3sum问题】
解法:时间复杂度为O(n^2)。如果数组已排序,利用解法1的双指针遍历法,可以在O(n)的时间内找到两个数之和等于一个給定的数。我们假设找到的三个数ai,aj,ak有ai<=aj<=ak,要让ai+aj+ak=sum,也就是要ai+aj=sum-ak,设subsum=sum-ak,很容易发现subsum的值只有n个,而确定ai+aj=subsum中的ai,aj只需要O(n)的时间,所以总的时间复杂度为O(nlogn+n*n)=O(n^2)
即:三个数字:首先还是先对数组进行排序,然后从i=0到n-1进行遍历,遍历arr[i]时,在调用上面的函数getSumNum(arr , Sum-arr[i])即可。
另:任意m个数字的想法:
首先还是先对数组进行排序,然后从i=0到n-1个元素遍历,遍历arr[i]时,在剩下的n-1个元素中调用getSumNum(arr,Sum-arr[i]),此时为求m-1个元素和为Sum-arr[i];接下来,同样的方法,从j=0到n-2个元素遍历,遍历arr[j]时在arr上递归调用getSumNum(arr,Sum-arr[i]-arr[j]),此时为求m-2个元素和为Sum-arr[i]-arr[j];依次递归,直到为求2个元素和为Sum-?-?-?...时为止。
另,不论是求3个数字还好是m个数字,总是能比较穷举法少一个数量级n,比先排序然后二分查找求Sum-arr[i]也要快。
扩展问题:如果输入的数组是没有排序的,但知道里面数字的范围,其他条件不变,如何在O(n)时间里找到这两个数字?
解法:扫一遍桶排序,然后前后再扫一遍。
http://zhedahht.blog.163.com/blog/static/25411174201131184017844/
//3sum问题,一个未排序数组中找和为sum的所有数对(a,b.c)
void threeSum(int arr[], int length, int sum){
sort(arr,arr+length);
for(int i=0;i<length;i++){
int j=i+1;
int k=length-1;
while(j<k){
if(arr[j]+arr[k]==sum-arr[i]){
cout<<arr[i]<<":"<<arr[j]<<":"<<arr[k]<<endl;
j++;
k--;
}
else if(arr[j]+arr[k]<sum-arr[i])
j++;
else //arr[j]+arr[k]>sum-arr[i]
k--;
}
}
}
3.8 数组循环移位
问题:设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量,如abcd1234循环右移三位,则为 abcd11234 ->4abcd123->34abcd12->234abcd1
出处:《编程之美》-2.17-数组循环移位
复杂:O(n)
解法:
假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右移了4位。比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把这两段看成两个整体。右移K位的过程就是把数组的两部分交换一下。变换的过程通过以下步骤完成:即 【mn->m'n'->(m'n')'=nm】1. 逆序排列abcd:abcd1234 → dcba1234;
2. 逆序排列1234:dcba1234 → dcba4321;
3. 全部逆序:dcba4321 → 1234abcd。
Reverse(int* arr, int b, int e)
{
for(; b < e; b++, e--)
{
int temp = arr[e];
arr[e] = arr[b];
arr[b] = temp;
}
}
RightShift(int* arr, int N, int k)
{
K %= N;
Reverse(arr, 0, N – K - 1);
Reverse(arr, N - K, N - 1);
Reverse(arr, 0, N - 1);
}
其中,由于很可能K>N不一定,所以使用语句;K=K%N;降低复杂度。
4,数学数字问题
4.1 求二进制数中1的个数
问题:对于一个字节的无符号整形变量,求其二进制表示中“1”的个数,要求算法的执行效率尽可能高。
出处:《编程之美》-2.1-求二进制数中1的个数
复杂:O(n)
解法1:利用整形数据除法的特点,通过相除和判断余数的值来分析
int Count(BYTE v)
{
int num = 0;
while(v)
{
if(v % 2 == 1)
{
num++;
}
v = v/ 2;
}
return num;
}
解法2:利用向右移位操作来达到上面的相处的效果
int Count(BYTE v)
{
int num = 0;
while(v)
{
num += v & 0x01;
v >>= 1;
}
return num;
}
解法3:
利用"v&(v-1)"来判断一个数是2^n【精妙,复杂度只与1的个数有关】
int Count(BYTE v)
{
int num = 0;
while(v)
{
v &= (v-1);
num++;
}
return num;
}
解法5:打表:
因为只是一个BYTE的整数,范围为0~255,索性预存一个256个数的数组countTable[256],保存每个数对应的1的个数会是多少,例如countTable[8]=3。
扩展问题:给定两个正整数A,B。判断A和B中有多少位是不同的?
解答:对A和B做异或,之后再数其中1的数量,Count(A ^ B),复杂度O(1+A和B位数不同的数量)。
4.2 阶乘n!末尾0的个数
问题:给定一个整数n,阶乘n!末尾有多少个0
出处:《编程之美》-2.2-不要被阶乘吓倒
复杂:O()
解法:问题转化为求N!中因子5的个数。
解法1:暴力法:把N!从1到N的每个数遍历一遍,算出每个数有多少个5组成。
ret = 0;
for(i = 1; i <= N ; i++)
{
j = i;
while(j % 5 == 0)
{
ret++;
j /= 5;
}
}
解法2:公式法:求N!中5的因子的个数Z
公式:Z = [N/5] +[N/5^2] +[N/5^3] + …(不用担心这会是一个无穷的运算,因为总存在一个K,使得5^K > N,[N/5^K]=0。)
[N/5] 表示不大于N的的数中5的倍数贡献一个5, [N/52] 表示不大于N的数中5^2的倍数再贡献一个5……
ret = 0;
while(N)
{
ret += N / 5;
N /= 5;
}
扩展问题:求N!的二进制表示中最低位1的位置
解法:问题转化为求N!中因子2的个数。
解法1:公式法:求N!中2的因子的个数Z
公式:Z = [N/2]+[N/4]+[N/8]+[N/16] +…
int lowestOne(int N)
{
int ret;
while(N)
{
N >>= 1;
ret += N;
}
return ret;
}
4.3 求解最大公约数
问题:给定整数a,b,求最大公约数gcd(a,b)
出处:《编程之美》-2.7-最大公约数问题
复杂:O()
解法1:欧几里得辗转相除法
基于原理:gcd(x, y)= gcd(y, y % x)(y > 0)
int gcd(int x, int y)
{
return (!y)?x:gcd(y, x%y);
}
解法2:辗转相减法
基于原理:模操作是瓶颈,设f(x,y)表示x,y的最大公约数,则有x-y也可以被k整除,即f(x,y)=f(y,x-y) (x>=y>0) 。如果x<y那么就可以先交换(x,y)因为(f(x,y)=f(y,x)),从而避免求一个正数和一个负数的最大公约数情况。
BigInt gcd(BigInt x,BigInt y)
{
if(x<y)
return gcd(y,x);
return (!y)?x:gcd(x-y,y);
}
缺点:如果是f(100000000000,1)就郁闷了
解法3:结合解法1和解法2
解法一的问题在于计算负责的大整数的除法,解法二的问题在于迭代次数太多,对于x,y如果x=k*x,y=k*y,那么f(y,x)=k*f(y1,x1),(具体过程看编程之美P152页)。另外如果x=p*x1,假设p是素数,并且y%p!=0(即y不能被p整除),那么f(x,y)=f(p*x1,y)=f(x1,y),注意到以上两点后,我们就可以对这两点算法进行改进。
最简单的方法:我们知道2是一个素数
1.若x,y都是偶数,f(x,y)=2*f(x/2,y/2)=2(x>>1,y>>1)
2.若x为偶数,y为奇数,f(x,y)=f(x/2,y)=f(x>>1,y)
3.若x为奇数,y为偶数f(x,y)=f(x,y/2)=f(x,y>>1)
4.若x为奇数,y为奇数f(x,y)=f(x,x-y),(x-y)之后是一个偶数,下一步一定会有除以2的操作
上面算法的时间复杂度为0(log2(max(x,y))).
//BigInt为自己实现的一个大整数类,IsEven()判断是否为偶数
BigInt gcd(BigInt x,BigInt y)
{
if(x < y)
return gcd(y,x);
if(y == 0)
return x;
else{
if(IsEven(x))
{
if(IsEven(y)) //情形1,x,y均为偶数
return 2 * gcd(x >> 1, y >> 1);
else //情形2,x为偶,y为奇
return gcd(x >> 1, y);
}
else
{
if(IsEven(y)) //情形3,x为奇,y为偶
return gcd(x, y >> 1);
else //情形4,x,y均为奇
return gcd(y, x - y);
}
}
}
4.4 逆转一个整数的二进制表示
问题:逆转一个整数的二进制表示,如把00001010变成01010000。
出处:《编程之美》-2.7-最大公约数问题
4.5 位运算实现两个整数的加减乘除运算
http://blog.csdn.net/luckyxiaoqiang/article/details/6886489
5,字符串算法
5.1 atoi算法
int atoi(char * s){
int sig = 1;
if(s[0]=='-'){
sig=-1;
s++;
}
int result = 0;
while(*s){
result=result*10+(*s-'0');
s++;
}
result*=sig;
return result;
}
5.2 itoa算法
char* itoa(int num, char *str, int radix){
char * t = str;
int sig = 1;
if(num<0){
sig = -1;
num = -num;
*t++='-';
}
char * p = t;
while(num){
*t++ = num%radix+'0';
num/=radix;
}
*t = '\0';
char * q = t-1;
while(p<q){
char temp = *p;
*p = *q;
*q = temp;
p++;
q--;
}
return str;
}
6,其他算法
6.1 主定理
6.2 全排列
void swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
//一个数组n项,从第i项开始排列a[i],a[i+1],...,a[n-1]
void perm(int a[], int i, int n)
{
//打印
if(i==n)
{
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
for(int j=i;j<n;j++)
{
swap(a[i],a[j]);
perm(a,i+1,n);
swap(a[i],a[j]);
}
}
6.3 判断质数
bool isPrime(int n){
assert(n>=1);
int mid = sqrt((double)n);
for(int i=2;i<=mid;i++){
if(n%i==0){
return false;
}
}
return true;
}
问题:数
出处:《
复杂:O(n)
解法:解
代码:解
输入两个串:
string midOrder = "HDIBJEKALFMCNGO";
string firstOrder = "ABDHIEJKCFLMGNO";
输出一棵二叉树。
算法思想很简单,在先序中的第一个节点一定是根节点,此节点在中序中的位置可以将中序分为左右两棵子树。如:
根为A,中序分为:HDIBJEK A LFMCNGO,这两棵子树在使用同样的方法就生成一棵树。