牛客算法(1)

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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值