1.判断平衡二叉树
描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
注:我们约定空树是平衡二叉树。
示例1
输入:{1,2,3,4,5,6,7}
返回值:true
方法:自顶向下
判断一个数是否为平衡二叉树。平衡二叉树是左子树的高度与右子树的高度差的绝对值小于等于1,同样左子树是平衡二叉树,右子树为平衡二叉树。
根据定义,如果我们能够求出以每个结点为根的树的高度,然后再根据左右子树高度差绝对值小于等于1,,就可以判断以每个结点为根的树是否满足定义。
我们可以用hash<TreeNode*, int>来存以每个结点的树的高度。
//平衡二叉树判断
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int val1,TreeNode *l = NULL,TreeNode *r = NULL){//构造函数
val = val1;
left = l;
right = r;
}
};
map<TreeNode*, int> hs;//每个结点为根的树的高度
int depth(TreeNode *root) {
if (!root) return 0;//为空
if (hs.find(root) != hs.end()) return hs[root];//
int ldep = depth(root->left);
int rdep = depth(root->right);//递归得到深度
return hs[root] = max(ldep, rdep) + 1;//得到每个结点为根的树的高度
}
bool judge(TreeNode *root) {
if (!root) return true;//为空返回true
return abs(hs[root->left] - hs[root->right]) <= 1 &&//深度小于等于1
judge(root->left) && judge(root->right);
}
bool IsBalanced_Solution(TreeNode* root) {
depth(root);//得出深度,每个结点为根的树的高度,采用map存储
return judge(root);//判断二叉树
}
调用:
TreeNode root=NULL;
cout<<IsBalanced_Solution(&root)<<endl;
2.两个栈实现队列
用两个栈来实现一个队列,分别完成在队列尾部插入整数(push)和在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
示例:
输入:[“PSH1”,“PSH2”,“POP”,“POP”]
返回:1,2
解析:
“PSH1”:代表将1插入队列尾部
“PSH2”:代表将2插入队列尾部
"POP“:代表删除一个元素,先进先出=>返回1
"POP“:代表删除一个元素,先进先出=>返回2
解题:
push操作就直接往stack1中push, pop操作需要分类一下:如果stack2为空,那么需要将stack1中的数据转移到stack2中,然后在对stack2进行pop,如果stack2不为空,直接pop就ok。
//两个栈实现队列
class stackSolutionList//push进入栈1,pop栈2出
{
public:
void push(int node) {
stack1.push(node);//push操作是将push进入栈1
}
int pop() {//pop操作是将栈2进行pop,在此之前需要将栈1的入栈2里面
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
int ret = stack2.top();
stack2.pop();
return ret;
}
private:
stack<int> stack1;
stack<int> stack2;
};
调用:
stackSolutionList stack_list;
stack_list.push(12);
stack_list.push(32);
stack_list.push(23);
cout<<"push12,push32,push23"<<endl;
cout<<"pop"<<stack_list.pop()<<endl;
cout<<"pop"<<stack_list.pop()<<endl;
cout<<"pop"<<stack_list.pop()<<endl;
结果:
3.最长无重复子数组
描述
给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组。
示例
输入:[2,2,3,4,3]
返回值:3
说明:[2,3,4]是最长子数组
条件:
1. 设置两个指针/索引,left = 0 right = 1;
2. map<int,int>,记录数组元素的 值-索引: value:index
设定:
1. left到right之间的元素为连续不重复;
2. map中存放left到right间元素的 值-索引 对;
3. 初始left right都在数组首部,从right++进数,从left–出数;
4. 进数: right++,检查map(含连续不重复子序列中所有元素) 中是否存在arr[right],不存在即不重复,向连续不重复子序列进数,加入map,right继续向前。
5. 出数: left–,以上检查map是否含arr[right]时,若存在,则需要从left段出数,即从map中吐出arr[left],并left++,直至arr[left]==arr[right],即一直吐到存在的和当前right所指同值元素。
6. 在每次进数出数的过程中,维护不重复子数组的最大长度maxLength = max{maxLength, map.size()}
/*
【双指针】
从右指针进数,从左指针出数
*/
int maxLength(vector<int>& arr) {
// write code here
//invalid input
if(arr.empty())
return 0;
//init
map<int,int> map; // value-index
int left = 0;
int right = 1;
map[arr[0]] = 0;
int maxLength = 0; //记录最大连续不重复子序列长度
//假设 left--right 为连续不重复段
while(left<=right && right<arr.size()){ //[left,right]
//待加入元素 arr[right]重复,先删除再加入
if(map.count(arr[right])){
//从left删除至与arr[right]等值元素
while(arr[left]!=arr[right]){
map.erase(arr[left]);
++left;
}
++left;
}
//加入arr[right]
map[arr[right]] = right;
maxLength = maxLength<map.size()? map.size():maxLength;
++right;
}
return maxLength;
}
调用:
int arr[9] = {1,8,6,2,5,4,8,3,7};
//通过数组a的地址初始化,注意地址是从0到9(左闭右开区间)
vector<int> vec_arr(arr, arr+9);
cout<<maxLength(vec_arr)<<endl;//7
4.大数相加
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
(字符串长度不大于100000,保证字符串仅由’0’~'9’这10种字符组成)
示例1
输入:“1”,“99”
返回值:“100”
说明:1+99=100
解题:
//大数相加
string bigtwoplus(string num1,string num2){
if(num1.size()<num2.size()){//把num1固定为位数较大的那个数,方便后面处理
string temp=num1;
num1=num2;
num2=temp;
}
int length1=num1.size(),length2=num2.size(),flag=0,a,b,sum;//flag是进位标记
while(length1>0){//从低位开始把对应的位相加
a=num1[length1-1]-'0';//获取num1当前位的数字
if(length2>0)//如果num2还没加完(注意,num2是位数较少的)
b=num2[length2-1]-'0';//获取num2当前位的数字
else
b=0;//如果num2加完了,num2对应位上就没有数来加了
//这时我没有break,因为虽然num2没有数字来加了,但可能还有进位需要加
sum=a+b+flag;//num1与num2对应位上的数字相加,再加上进位位
if(sum>=10){//如果加起来大于于10,那就需要进位了
num1[length1-1]='0'+sum%10;//计算加完之后,当前位应该是多少
flag=1;//把进位标记置1
}else{
num1[length1-1]='0'+sum;//计算加完之后,当前位应该是多少
flag=0;//把进位标记置0
}
length1--;//向高位移动1位
length2--;//向高位移动1位
}
//如果两个数对应位都加完了,进位位是1,说明位数要增加1了
//比如99+1,加完之后,变成了三位数100,其实就是再在前面加一位1
if(1==flag)
num1="1"+num1;
return num1;
}
调用:
string num1;
string num2;
while(cin>>num1>>num2)
{
cout<<"num1:"<<num1<<endl;
cout<<"num2:"<<num2<<endl;
cout<<"sum:"<<bigtwoplus(num1,num2)<<endl;
}
结果:
代码来源:https://blog.csdn.net/OrthocenterChocolate/article/details/36664901
5.最长回文子串
描述
对于一个字符串,请设计一个高效算法,计算其中最长回文子串的长度。
给定字符串A以及它的长度n,请返回最长回文子串的长度。
示例1
输入:“abc1234321ab”,12
返回值:7
动态规划
图示:dp[i][j]表示A[i:j] 是否为回文串
int getLongestPalindrome(string A, int n) {
// write code here
int dp[n][n]; // dp[i][j] 表示A[i:j] 是否是回文串
int max_len = 0; //最长回文子串的长度
memset(dp, 0, sizeof(dp));
//从尾到头
for(int i = n-1;i>=0; i--){
//从左到右
for(int j = i;j<n;j++){
int len = j-i+1; //子串长度
if(A[i]==A[j]){ // 如果A[i],A[j]相等
dp[i][j] = len<=2 ? 1 : dp[i+1][j-1]; //len<=2那么就为回文串,len>2: dp[i][j] = dp[i+1][j-1]
}
if(dp[i][j]) max_len = max(max_len,len); //如果A[i:j] 为回文串,那么就从maxlen与len之间取大的
}
}
return max_len;
}
来源https://www.nowcoder.com/