剑指offer系列(六)
题目描述:
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList,例如按照链表顺序,1->2->3->4->5->6->7->8,那么我们将得到{8,7,6,5,4,3,2,1}
题目分析:
对于单向链表我们知道,一个值与下一个值一一连接,而将值反向输出,我们可以用一个容器存起来,然后反向遍历输出结果,不过我们有一个更好的容器可以实现这一功能,那就是栈,栈具有先入后出的特点,所以我们将链表的值通过栈存起来,然后弹出就是我们需要的结果
下面是代码:
#include <iostream> #include<vector> #include<stack> #include<algorithm> using namespace std; struct ListNode { int value; struct ListNode *next; ListNode(int x) : value(x), next(NULL) { } }; vector<int> AlterLinkNode(ListNode* head) { vector<int> result; stack<ListNode*> arr; ListNode *p = head; while (p!=NULL) { arr.push(p); p = p->next; } while (!arr.empty()) { result.push_back((arr.top())->value); arr.pop(); } }
或者我们还可以采用向量插入的特性实现反向输出
#include<iostream> #include<vector> using namespace std; struct ListNode{ int value; struct ListNode* next; ListNode(int x):value(x),next(NULL){} }; def AlterLinkNode(ListNode* head){ if(head==NULL) return false; ListNode *p=head; vector<int> result; while(p!=NULL){ result.insert(p->value,p.begin()); p = p->next; } return result; }
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回
题目分析:
首先简单回顾一下前序遍历,中序遍历和后序遍历的特点,前序遍历可以分成{根节点,左子树,右子树},而中序遍历可以分成{左子树,根节点,右子树},后序遍历可以分成{左子树,右子树,根节点},根据前序遍历的特点,我们知道第一个值必定为根节点,以前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}为例,1为初始根节点,通过查找中序遍历,我们可以划分出中序遍历的左子树{4,7,2},右子树{5,3,8,6},对应的前序遍历的左子树为{2,4,7},右子树为{3,5,6,8},接着,我们需要确定原二叉树的左子树,所以我们将前序遍历的左子树与中序遍历的左子树重新送入这个重建二叉树函数,递归算法得到左子树分布,同样的前序遍历的右子树与中序遍历的右子树重新送入重建二叉树函数,递归算法得到右子树分布,到此程序流程结束。
下面是代码:
struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { if(pre.size()<=0) return NULL; TreeNode* root = new TreeNode(pre[0]); for(int i=0;i<pre.size();i++){ if(vin[i]==pre[0]){ root->left = reConstructBinaryTree(vector<int>(pre.begin()+1,pre.begin()+i+1),vector<int>(vin.begin(),vin.begin()+i)); root->right = reConstructBinaryTree(vector<int>(pre.begin()+i+1,pre.end()),vector<int>(vin.begin()+i+1,vin.end())); } } return root; } };
链表知识点回顾
链表,想象成一串铰链,从头到尾一一连接,一般与数组比较,在插入和删除操作时具有更为快捷的特点,数组需要o(n)的时间,而链表则需要o(1)就可以实现,我们采用结构体实现这一结构,如下所示,为单向链表,第一个数具有值value和next这两个属性,后置是与下一个链表相连的重要依据,初始化我们将next置空
struct ListNode { int value; struct ListNode *next; };
链表插入操作,我们令原来p节点下一个是m节点,那么会有等式m = p->next,那么我们想要插入节点node,注意,只有一种顺序,首先node->next = m,然后p->next = node,然后我们将m替换为p->next插入就完成了,那为什么不能先p->next = node,然后node->next = m呢,因为这样会导致m地址丢失
void InsertNode(ListNode*p,int target) { ListNode *node = new ListNode; node->value = target; node->next = p->next; p->next = node; }
链表删除操作
void DeleteNode(ListNode*p) { p->value = p->next->value; p->next = p->next->next; }
参考: