笔试算法题(05):转换BST为双向链表 & 查找栈中的最小元素

出题:把二元查找树转变成排序的双向链表。输入一棵二元查找树,要求将该二元查找树按照中序转换成一个排序的双向链表,要求不能创建任何新的节点,只能调整指针的指向;

分析:

  • 递归的思路,当前节点需要进行的处理,并使用递归调用和返回值将子问题链接起来;

  • 首先明白二元查找树的特性,变成有序双向链表后当前根节点的左节点为其原来左子树的最右节点,右节点为其原来右子树的最左节点;因此策略就是针对当前根节点索引的子树,首先判断其为上层节点的右子树还是左子树,从而决定返回最右还是最右节点;然后再递归处理当前根节点的左右子树;

解题:


 1 #include <stdio.h>
2 #include <malloc.h>
3 #include <string.h>
4
5 typedef struct Node {
6 int value;
7 Node *left;
8 Node *right;
9 } *NodePtr;
10
11 Node* MostLeft(Node *current) {
12 Node* temp=current;
13 while(temp->left!=NULL) {
14 temp=temp->left;
15 }
16 return temp;
17 }
18
19 Node* MostRight(Node *current) {
20 Node* temp=current;
21 while(temp->right!=NULL) {
22 temp=temp->right;
23 }
24 return temp;
25 }
26
27 Node* Transfer(Node *current, bool isRight) {
28
29 if(current==NULL) return NULL;
30 /**
31 * 在树结构被破坏之前预先查找好需要返回的节点
32 * */
33 Node* turnback = (isRight ? MostLeft(current) : MostRight(current));
34 /**
35 * 递归处理左右子树,将具体返回的节点推迟到子树解决
36 * */
37 if(current->left!=NULL) {
38 current->left=Transfer(current->left,false);
39 current->left->right=current;
40 }
41 if(current->right!=NULL) {
42 current->right=Transfer(current->right,true);
43 current->right->left=current;
44 }
45 /**
46 * 根据isRight的值,和current是否有左右子树返回不同的节点
47 * */
48 return turnback;
49 }

出题:定义stack数据结构,除Push和Pop函数外要求增加Min函数,其功能是找到stack中最小的元素,要求所有函数时间复杂度都是O(1);

分析:

  • 使用辅助stack结构依次将目前的最小元素压入栈,设置CurMin元素记录当前stack中的最小元素,每次Push的新元素都与CurMin比较,若新元素更小则将其压入辅助栈;每次Pop元素都与CurMin比较,若就是CurMin元素则将辅助栈栈顶元素出栈;

解题:


 1 class MyStack {
2 private:
3 int *array;
4 int capability;
5 int length;
6 int head;
7 int tail;
8 public:
9 MyStack(int n=10): array((int*)malloc(sizeof(int)*n)), head(0),tail(0),capability(n), length(0) {}
10 ~MyStack() {delete [] array;}
11
12 bool isFull() {
13 if(length == capability) return true;
14 return false;
15 }
16 bool isEmpty() {
17 if(length == 0) return true;
18 return false;
19 }
20 /**
21 * head当前的指向位置是下一次将push的元素的
22 * */
23 bool push(int n) {
24 if(isFull()) return false;
25 array[head]=n;
26 head=(head+1)%(capability+1);
27 length++;
28 return true;
29 }
30 /**
31 * tail当前指向的位置是下一次将pop的元素的
32 * */
33 bool pop(int *n) {
34 if(isEmpty()) return false;
35 *n=array[tail];
36 tail=(tail+1)%(capability+1);
37 length--;
38 return true;
39 }
40
41 void showStack() {
42 int i=tail;
43 int temp=length;
44 printf("\nnew path\n");
45 while(temp>0) {
46 printf("%d, ",array[i++]);
47 temp--;
48 }
49 }
50 };
51
52
53 class MinStack {
54 private:
55 MyStack *mainStack;
56 MyStack *assiStack;
57 int curMin;
58 public:
59 MinStack(): mainStack(new MyStack()),assiStack(new MyStack()),curMin(0) {}
60 /**
61 * 仅当出现新的最小元素时,才将前一个最小元素压入assiStack
62 * */
63 bool push(int n) {
64 if(mainStack->push(n)) {
65 if(n<curMin) {
66 assiStack->push(curMin);
67 curMin=n;
68 }
69 return true;
70 }
71 return false;
72 }
73 /**
74 * 仅当mianStack的pop元素等于curMin时,才从assiStack中新pop出一个元素
75 * */
76 bool pop(int *n) {
77 if(mainStack->pop(n)) {
78 if(*n == curMin) {
79 int *temp;
80 assiStack->pop(temp);
81 curMin=*temp;
82 }
83 return true;
84 }
85 return false;
86 }
87 int min() {
88 return curMin;
89 }
90 };

时间: 2024-10-23 07:16:35

笔试算法题(05):转换BST为双向链表 & 查找栈中的最小元素的相关文章

笔试算法题(24):找出出现次数超过一半的元素 &amp; 二叉树最近公共父节点

出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字: 分析: 解法1:首先对数组进行排序,时间复杂度为O(NlogN),由于有一个数字出现次数超过了数组的一半,所以如果二分数组的话,划分元素肯定就是这个数字: 解法2:首先创建1/2数组大小的Hash Table(哈希表可以替代排序时间,由于一个数字出现超过了数组的一半,所以不同元素个数肯定不大于数组的一半),空间复杂度O(N),顺序扫描映射数 组元素到Hash Table中并计数,最后顺序扫描Hash Table,计数超过数组

笔试算法题(34):从数字序列中寻找仅出现一次的数字 &amp; 最大公约数(GCD)问题

出题:给定一个数字序列,其中每个数字最多出现两次,只有一个数字仅出现了一次,如何快速找出其中仅出现了一次的数字: 分析: 由于知道一个数字异或操作它本身(X^X=0)都为0,而任何数字异或操作0都为它本身,所以当所有的数字序列都异或操作之后,所有出现两次的数字异或操作之后的结果都为0,则最后剩下的结果就是那个仅出现了一次的数字: 如果有多个数字都仅仅出现了一次,则上述的异或操作方法不再适用:如果确定只有两个数字只出现了一次,则可以利用X+Y=a和XY=b求解: 解题: 1 int findSin

笔试算法题(15):-1到N中包含1的数字的个数 &amp; 连续和为N的序列

出题:输入一个整数N,求从1到N这N个整数的十进制表示中'1'出现的次数: 分析: 从左向右处理string表示的数字:当前数字长度为n,判断最左边一位数字字符: 如果是0,则直接递归下一位: 如果是1,则计数有两个来源,一个是n位数数字(实际就是除去最高位之后的数字大小,加上1,当其余位全部为0的时候),另一个是n-1,n-2,--,1位数字,使用SpecialPower可以计算: 如果是其他数字,则计数有两个来源,一个是n,n-1,n-2,--,1位数字,使用SpecialPower可以计算

笔试算法题(14):整数二进制表示中的1 &amp; 判定栈的push和pop序列是否对应

出题:输入一个整数,要求计算此整数的二进制表示中1的个数 分析: 如果整数表示为k,当其是负数的时候,使用1<<i分别检测k的每一位:当其位整数的时候,则k/2表示将其二进制表示右移一位,k%2 ==0表示其是否是偶数,如果不是则说明当前二进制表示的最右边一位为1,当k==0成立的时候移位结束: 另外还可以使用'消1'的方法,如果二进制表示A为'****1000',则A-1为'****0111',也就是我们仅关注二进制表示最右边的第一个 1,这样的话A&(A-1)的结果就可以将最右边的

笔试算法题(09):查找指定和值的两个数 &amp; 构造BST镜像树

出题:输入一个已经升序排序的数组和一个数字:要求在数组中查找两个数,这两个数的和正好等于输入的那个数字,输出任意一对数字就可以,要求时间复杂度是O(n): 分析:对于升序排序的数组{-i-j-k-m--},只有可能是i+m=j+k(j和k可能是同一个数),所以可以从两边往中间收缩而忽视其他交叉相加的情况: 解题: 1 void FindSumFactor(int *array, int length, int sum) { 2 int left=0, right=length-1; 3 whil

笔试算法题

转自:http://www.cnblogs.com/xwdreamer/archive/2011/12/13/2296910.html 1.把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向.   10  / \  6  14 / \ / \4  8 12 16 转换成双向链表4=6=8=10=12=14=16.  首先我们定义的二元查找树 节点的数据结构如下: struct BSTreeNode{  i

笔试算法题(51):简介 - 红黑树(RedBlack Tree)

红黑树(Red-Black Tree) 红黑树是一种BST,但是每个节点上增加一个存储位表示该节点的颜色(R或者B):通过对任何一条从root到leaf的路径上节点着色方式的显示,红黑树确保所有路径的差值不会超过一倍,最终使得BST接近平衡: 红黑树内每个节点包含五个属性:color, key, left, right和p,p表示指向父亲节点的指针:一棵BST需要同时满足下述五个性质才能称作红黑树: 每个节点只能是红色或者黑色节点中的一种: 根节点必须是黑色: 每个叶节点(NULL)必须是黑色:

笔试算法题(47):简介 - B树 &amp; B+树 &amp; B*树

B树(B-Tree) 1970年由R. Bayer和E. Mccreight提出的一种适用于外查找的树,一种由BST推广到多叉查找的平衡查找树,由于磁盘的操作速度远小于存储器的读写速度,所以要求在尽量少 的操作次数内完成CPU分配的任务,B树就按照此原则设计,B树与红黑树的主要区别在于B树节点可以有超过2个子女,从而大大降低树的高度以减少查询时 间: 一棵M阶B树(Balanced Tree of Order M)是一棵平衡的M路搜索树,满足性质: 根节点至少有两个子女: 除根节点和叶子节点外的

笔试算法题(39):Trie树(Trie Tree or Prefix Tree)

出题:TRIE树 (Trie Tree or Prefix Tree): 分析: 又称字典树或者前缀树,一种用于快速检索的多叉树结构:英文字母的Trie树为26叉树,数字的Trie树为10叉树:All the descendants of a node have a common prefix of the sequence associated with that node, and the root is associated with the empty sequence. 由于不同的se