文章目录
21.举例让抽象具体化:栈的压入、弹出序列
题目描述:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
解法思路:
模拟压栈过程,建立辅助栈,
(1)将压栈序列元素压入辅助栈,比较压入元素与出栈序列栈顶元素大小;
(2)当压入元素不等于出栈序列栈顶元素时,比较压栈序列下一个元素与出栈序列栈顶元素相对大小;
(3)当压入元素等于出栈序列栈顶元素时,辅助栈将此元素出栈,接下来与出栈序列下一个元素比较。
(4)循环执行(2)-(3);
(5)判断:最后辅助栈为空则出栈序列为入栈序列的子序列,否则不是。
举例:
压栈:1,2,3,4,5
出栈:4,5,3,2,1
(1)1 ≠ 4,将1压入辅助栈,压入指针后移一位,比较下一个元素;
(2)2 ≠ 4,3 ≠ 4,依次将2,3压入辅助栈,压入指针后移一位,比较下一个元素;
(3)4 = 4,将4出栈,弹出指针后移一位,比较下一个元素;
(5)5 ≠ 3,将5压入辅助栈,压入指针后移一位,比较下一个元素;
(6)此时入栈元素已全部压入辅助栈,将辅助栈元素与出栈序列中未出栈的元素一一对比,判断是否能够完全出栈;
(7)辅助栈栈顶元素为5,与出栈序列栈底元素比较, 5 = 5,将5出栈;
(8)3 =3, 2 = 2, 1 = 1,依次出栈。
判断:最后辅助栈为空则出栈序列为入栈序列的子序列,否则不是。
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if (pushV.empty() || popV.empty())
return false;
stack<int> assV;
int len = pushV.size();
int i = 0;
int j = 0;
while (i < len) {
assV.push(pushV[i]);
while (assV.top() == popV[j] && j < len) {
assV.pop();
j++;
}
i++;
}
if (assV.empty())
return true;
else
return false;
}
};
22.举例让抽象具体化:从上往下打印二叉树
题目描述:
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
解法思路:
类比广度遍历,建立辅助队列存储下一次要输出的结点,通过循环依次输出即可;
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
vector<int> result;
if (!root)
return result;
vector<TreeNode*> ass;
TreeNode *p = NULL;
ass.push_back(root);
while (!ass.empty()) {
vector<TreeNode*> temp;
for (int i = 0; i < ass.size(); i++) {
result.push_back(ass[i]->val);
if (ass[i]->left)
temp.push_back(ass[i]->left);
if (ass[i]->right)
temp.push_back(ass[i]->right);
}
ass.swap(temp);
temp.clear();
}
return result;
}
};
23.举例让抽象具体化:二叉搜索树的后序遍历序列
题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解法思路:
递归思想,最后一个元素为二叉搜索树根结点,左子树都小于根结点,右子树都大于根结点,因此可将左右子树分别找出来,继续递归。
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
if (sequence.empty())
return false;
return isPostOrder(sequence, 0, sequence.size()-1);
}
bool isPostOrder(vector<int>sequence, int begin, int end) {
if (begin == end)
return true;
int mid = begin;
while (sequence[mid++] < sequence[end] && mid < end)
;
int temp = mid;
while (sequence[temp++] > sequence[end] && temp < end)
;
if (temp < end)
return false;
bool left = true, right = true;
if (mid > begin)
left = isPostOrder(sequence, begin, mid-1);
if (mid < end - 1)
right = isPostOrder(sequence, mid+1, end-1);
return left && right;
}
};
代码分析:下面代码内存超出要求,分析?
class Solution {
public:
bool VerifySquenceOfBST(vector<int> sequence) {
if (sequence.empty())
return false;
return isPostOrder(sequence, 0, sequence.size()-1);
}
bool isPostOrder(vector<int>sequence, int begin, int end) {
if (begin == end)
return true;
int mid = begin;
while (sequence[mid++] < sequence[end] && mid < end)
;
int temp = mid;
while (sequence[temp++] > sequence[end] && temp < end)
;
if (temp < end)
return false;
bool left = true, right = true;
if (mid == begin || mid == end)
return isPostOrder(sequence, begin, end-1);
else {
left = isPostOrder(sequence, begin, mid-1);
right = isPostOrder(sequence, mid+1, end-1);
return left && right;
}
}
};
24.举例让抽象具体化:二叉树中和为某一值的路径
题目描述:
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)。
解法思路:
首先思考节点值的和为输入的整数,每条路径都一定是从根节点到叶子节点,在数据结构中从根节点到叶子节点的遍历称之为深度优先遍历DFS。
因此整个过程可以采用先序遍历方式的DFS,即根节点->左子树->右子树。
随后考虑一次遍历完成后的处理:
当一次遍历完成后:
如果输入整数值恰好等于节点值之和,则输出这条路径并且回退一个节点;
如果不等于则直接回退一个节点,即回退到当前节点的父节点,如果该父节点有右孩子,则继续遍历,否则继续回退。
考虑回退到根节点,此时如果它有右孩子,则继续遍历,否则整个DFS结束;
每一轮递归返回到父结点时,当前路径也应该回退一个结点(回溯法)。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
vector<vector<int> > result;
vector<int> trace;
if(!root)
return result;
dfsFind(root, expectNumber, result, trace);
return result;
}
//此处定义为 void dfsFind(TreeNode* root, int expectNumber, vector<vector<int> > &result, vector<int> trace)亦可,其中trace可传值,也可传引用
//原因:trace值的改变是在dfsFind()中发生的,赋值过程也是在dfsfind()中完成的,在赋值之后,只需要改变result中的值即可,trace中数值已没有意义
void dfsFind(TreeNode* root, int expectNumber, vector<vector<int> > &result, vector<int> &trace) {
trace.push_back(root->val);
if (!root->left && !root->right) {
if (root->val == expectNumber)
result.push_back(trace);
}
if (root->left)
dfsFind(root->left, expectNumber - root->val, result, trace);
if (root->right)
dfsFind(root->right, expectNumber - root->val, result, trace);
trace.pop_back();
}
};
25.分解让复杂问题简单:复杂链表的复制
题目描述:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
算法思路:
算法思路
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead) {
if (!pHead)
return NULL;
nodeClone(pHead);
connectRandom(pHead);
return splitList(pHead);
}
//复制结点
void nodeClone(RandomListNode* pHead) {
RandomListNode* p = pHead;
while (p != NULL) {
RandomListNode* newNode = new RandomListNode(p->label);
RandomListNode* temp = p->next;
p->next = newNode;
newNode->next = temp;
p = temp;
}
}
//连接随机结点
void connectRandom(RandomListNode* pHead) {
RandomListNode* p = pHead;
while (p) {
RandomListNode* pClone = p->next;
if (p->random)
pClone->random = p->random->next;
p = pClone->next;
}
}
RandomListNode* splitList(RandomListNode* pHead) {
RandomListNode* head = pHead->next;
RandomListNode* p = pHead;
while (p) {
RandomListNode *pClone = p->next;
p->next = pClone->next;
p = p->next;
if (p != NULL)
pClone->next = p->next;
}
return head;
}
};