Day12-学习内容
1.剑指Offer
面试题8:二叉树的下一个节点
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:1.按该节点有无右子树分两种情况讨论;
2.当有右子树时,下一个节点为该节点右子树的最左子节点。
3.当无右子树时,再分该节点是否为父节点的右子节点,若是右子节点,则向上遍历找到一个是它父节点作为左子节点的父节点作为要找的下一个节点;若不是右子节点,则该节点的父节点就是下一个节点。
方法:学会自顶向下、逐步分解地分析问题,综合运用举例、画图、分类的方法去解决问题。
代码:
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==nullptr){
return nullptr;
}
TreeLinkNode* pNext=nullptr;
if(pNode->right!=nullptr){
TreeLinkNode* pRight=pNode->right;
while(pRight->left!=nullptr){
pRight=pRight->left;
}
pNext=pRight;
}
else if(pNode->next!=nullptr){
TreeLinkNode* pCurrent=pNode;
TreeLinkNode* pParent=pNode->next;
while(pParent!=nullptr&&pCurrent==pParent->right){
pCurrent=pParent;
pParent=pParent->next;
}
pNext=pParent;
}
return pNext;
}
};
面试题45:把数组排成最小的数
题目描述:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路:1.对vector容器内的数据进行排序,按照将a和b转为string后,若 a+b<b+a, 则a排在在前的规则排序,如 2 21 因为 212 < 221 所以 排序后为 21 2。
2.
to_string() 可以将int 转化为string。
3.
C++ sort排序函数用法
https://blog.csdn.net/w_linux/article/details/76222112
4.C++在类成员函数前加static的作用
https://blog.csdn.net/lulu_6666/article/details/79570335
代码:
class Solution {
public:
string PrintMinNumber(vector<int> numbers) {
string answer="";
sort(numbers.begin(),numbers.end(),cmp);
for(int i=0;i<numbers.size();i++){
answer+=to_string(numbers[i]);
}
return answer;
}
static bool cmp(int a,int b){
string A="";
string B="";
A+=to_string(a);
A+=to_string(b);
B+=to_string(b);
B+=to_string(a);
return A<B;
}
};
注意:cmp函数前必须加static,否则会报错。
面试题34:二叉树中和为某一值的路径
题目描述:
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
思路:从根结点开始,当每访问到一个结点,我们把该结点添加到路径上,并累加该结点的值。如果该结点为叶结点并且路径中结点值的和刚好等于输入的整数,则当前路径符合要求,我们把它打印出来。如果当前不是叶子结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到它的父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是从根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是一个栈,因为路径要与递归调用状态一致,而递归调用的本质就是一个压栈和出栈的过程。
代码:
class Solution {
public:
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
int currentNum=0;
vector<vector<int>> Path;
vector<int> tempPath;
FindPathCore(root,expectNumber,currentNum,tempPath,Path);
return Path;
}
void FindPathCore(TreeNode* root,int expectNumber,int ¤tNum,vector<int> &tempPath,vector<vector<int>> &Path){
if(root){
currentNum+=root->val;
tempPath.push_back(root->val);
if(!root->left&&!root->right){
if(currentNum==expectNumber){
Path.push_back(tempPath);
}
}
else{
if(root->left){
FindPathCore(root->left,expectNumber,currentNum,tempPath,Path);
}
if(root->right){
FindPathCore(root->right,expectNumber,currentNum,tempPath,Path);
}
}
currentNum-=root->val;
tempPath.pop_back();
}
}
};
注意:此题要求按数组长度由大到小排列输出结果,但好像程序中并没有体现也一样通过了所有测试用例,个人觉得还需要加入一步对数组长度的排序,再输出结果,不知道是不是因为用的是vector容器由有自动排序功能所以通过了测试用例,这点再后面作为优化的点再完善和补充。
2.Leetcode
例1:求从根节点到叶子节点的所有路径和。
题目描述:
Given a binary tree containing digits from0-9only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path1->2->3which represents the number123.
Find the total sum of all root-to-leaf numbers.
For example,
1 / \ 2 3
The root-to-leaf path1->2represents the number12.
The root-to-leaf path1->3represents the number13.
Return the sum = 12 + 13 =25.
思路:从根结点开始,当每访问到一个结点,我们把该结点添加到路径上,并
"累加"该结点的值,这里"累加"
的含义指的是按照题目的要求组成相应的数字即
"左移"
后相加。如果该结点为叶结点,那么一条路径搜索完成,将当前所得结果累加。如果当前不是叶子结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到它的父结点。因此我们在函数退出之前要在路径上"删除"
当前结点,做法就是将当前路径值/10,以确保返回父结点时路径刚好是从根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是一个栈,因为路径要与递归调用状态一致,而递归调用的本质就是一个压栈和出栈的过程。
代码:
class Solution {
public:
int sumNumbers(TreeNode *root) {
int pathSum=0;
int sum=0;
sumNumbersCore(root,pathSum,sum);
return sum;
}
void sumNumbersCore(TreeNode *root,int &pathSum,int &sum){
if(root){
pathSum=pathSum*10+root->val;
if(!root->left&&!root->right){ //如果是叶子节点,一条路径搜索完成,累加到sum
sum+=pathSum;
}
//如果不是叶子节点,则遍历它的子结点
else{
if(root->left){
sumNumbersCore(root->left,pathSum,sum);
}
if(root->right){
sumNumbersCore(root->right,pathSum,sum);
}
}
//返回父结点之前,路径上“删除”当前节点
pathSum/=10;
}
}
};
例2:简化字符串表示的路径
题目描述:
Given an absolute path for a file (Unix-style), simplify it.
For example,
path ="/home/", =>"/home"
path ="/a/./b/../../c/", =>"/c"
Corner Cases:
- Did you consider the case where path ="/../"?
In this case, you should return"/". - Another corner case is the path might contain multiple slashes'/'together, such as"/home//foo/".
In this case, you should ignore redundant slashes and return"/home/foo".
思路:
1.通过stringstream以及getline取子串
getline(ss,sub,'/')
getline()的原型是istream& getline ( istream &is , string &str , char delim );
其中 istream &is 表示一个输入流,譬如cin;
string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);
char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为'\n',也就是回车换行符(遇到回车停止读入)。
https://blog.csdn.net/best_fiends_zxh/article/details/53064771
2.C++中常见的输入输出
1)cin :可接受数字、字符串
2)cin.get() :
cin.get(字符变量名)可以用来接收字符
cin.get(字符数组名,接收字符数目)用来接收一行字符串,可以接收空格
3)cin.getline() :接受一个字符串,可以接收空格并输出
4)getline() :接受一个字符串,可以接收空格并输出,需包含“#include”
5)gets(): 接受一个字符串,可以接收空格并输出,需包含“#include”
https://blog.csdn.net/czh1075208140/article/details/79698441
3.C++中字符串的表示
1)字符数组(使用初始化列表)
char str1[11]={‘c’,’h’,’a’,’r’,’ ‘,’a’,’r’,’r’,’a’,’y’,’\0′};
字符数组中显式地包含空字符’\0’;
2)字符数组(使用双引号字符串常量)
char str2[11]=”char array”;
字符数组隐式包含空字符’\0’;”char array”存储在栈上;
不能如下操作;;
char str2[11];
str2=”char array”;
“”之间的字符不能超过10个(即使是11个字符也不行),否则编译报错。因为该字符数组,末位已隐式包含’\0’。
3)使用字符串指针
const char *str2=”this”;
str2位字符指针,指针指向”this” 字符串的首地址。
注意最好使用关键字const ,否则编译时会有warning提示。因为”this”字符串常量,存储在常量存储区,只能读,不能修改。
4)使用string类
string str4 =”this is a string!”;
注意:与python不同,在C++中用单引号表示字符,双引号表示字符串。
https://blog.csdn.net/ivnetware/article/details/53457703
代码:
class Solution {
public:
string simplifyPath(string path) {
vector<string> res;
stringstream ss(path);
string sub;
while(getline(ss,sub,'/')){
if(sub=="."||sub==""){
continue;
}
else if(sub==".."&&res.size()){
res.pop_back();
}
else if(sub!=".."){
res.push_back(sub);
}
}
string result;
for(string temp:res){
result+='/'+temp;
}
return res.empty()?"/":result;
}
};