【2020-10-13】LeetCode每日5题总结

1 求数中最多连续的1

左移一次和原数相与,直到变为0,计操作次数既是最多连续的1。(题解来自:Mcdull
应用:LeetCode211.最大正方形
求1组成的正方形的宽
正常解法:
暴力求解的话就是穷举,遍历二维数组将每一个1作为正方形的左上角,如果想扩大正方形,则新增一行一列且必须由连续1组成。

  • 如何判断新增的一行一列是否是连续的1?令k从1开始直到目前可达最大宽/高(min{宽、高}),这里的宽是row-i,高是col-j。即k是可以增加的区域。
    令m是从0-k,这样可以遍历到增加的一行和一列的所有元素
/**
* 判断新增的行列是否合法
*/
for(int k=1;k<maxWidth-j;k++){
	if(a[i+k][j+k]!='1'){
		break;
	}
	//flag表示这新增的一行一列是否合法
	boolean flag = true;
	for(int m=0;m<k;m++){
		if(a[i+k][j+m]!='1'||a[i+m][j+k]!='1'){
			flag = false;//因为这里只能跳一层循环所以需要一个flag来跳第二层k的循环
			break;
		}
	}
	//如果合法就更新maxSide
	if(flag){
		maxSide = Math.max(maxSide,1+k);
	} else {
		break;
	}
}
  • 遍历时间复杂度O(mn)
  • 为了凑成正方形,需要遍历判断正方形内每个数是不是1,所以需要取宽、高中较小值的平方。总的时间复杂度为O(mn*min(m,n)^2)

优化解法

减少重复遍历,需要用到动态规划。这次不再从左上角开始考虑正方形,而是从右下角,这样可以用到之前遍历左上部分时的数据。
使用dp(i,j)表示以i,j为右下角的最大正方形边长,可以得到:

  • 如果a[i][j]为0而不是1,则不可能组成正方形的
  • 如果a[i][j]为1,则正方形边长由其左、左上、上方的元素决定。但如果i,j本身是在边界上,那么最大边长只能为1.
    为什么由其左、左上、上方的元素决定?i,j相当于在其左上元素往右往下增加了一列一行,那么可以得到
    dp[i][j] = min{dp[i-1][j],dp[i][j-1],dp[i-1][j-1]}+1
    其左、左上、上方dp的最小值+1
  • 这样,遍历所有元素一遍即可求出所有dp,在求dp的过程中记录最大值。时间复杂度为O(mn)
  • 空间复杂度为O(mn)

2 求完全二叉树的节点个数

LeetCode222.完全二叉树的节点个数
首先,这道题可以用遍历二叉树来解决,但考虑完全二叉树的性质:

  • 它是一颗空树,或者,它的叶子节点只出现在最后两层,且最后一层如果不满则叶子结点聚集在左侧。
  • 那么我们可以求root左右子树的高度,如果left>right则说明左子树比右子树高一层,右子树成为满二叉树,其节点数为Math.pow(2,right)-1(root没有计算在内)。

满二叉树节点计算:如果层数为n,则满二叉树节点数为2^n-1

  • 如果left==right说明左子树是满二叉树,右子树左侧聚集了最后一层剩下的叶子结点。那么继续对右子树进行递归统计。

小技巧:如何计算2^n?可以通过1左移n位来进行位运算。

那么,最后需要解决的就是如何计算完全二叉树的层数?
完全二叉树的右子树只有可能小于或等于左子树的层数,所以只要遍历左节点就可以了

while(cur!=null){
	depth++;
	cur=cur.left;
}

这样就省去递归了
但是仍然需要递归求解左或右子树的节点数(满二叉树那一边可以直接得到,即加上root节点是2^n,然后递归另一个子树即可)
参考题解:Wanglihao

3 矩形重叠后的总面积

LeetCode223.矩形面积
这里需要注意的是当测试数据为-1500000000 - 1500000000时计算结果会超出int的最小值导致溢出,所以要保证取CG最小值要大于AE最大值才有意义。
重叠面积的宽为右上角横坐标最小值-左下角横坐标最大值
高同理
参考题解:燕少江湖

4 基本计算器

实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
LeetCode224. 基本计算器
(在金山云的面试里遇见过这道题,不过当时没有选。现在一看难度是困难= =)
思路:从右往左遍历字符串,如果遇到(说明要计算一个括号()内结果,则不断出栈直到遇到),然后计算这一段的结果,我们用一个方法calInStack()来完成。
该方法有这么些个功能:

  • 出栈开始计算
  • 翻转字符串得到正常的表达式(主函数中从右往左遍历
  • 遇到)则结束,不再继续弹出
  • 鉴于该计算方法关注左右括号,那么需要把原始字符串用括号扩起来,避免最后的元素没有被计算
    calInStack()实现:
private static int calInStack(Stack<Object> st){
	int res = 0;
	//取出栈顶数字
	if(!st.isEmpty()){
		res = (int)st.pop();
	}
	//继续取和计算
	while(!st.isEmpty()&&(char)st.peek()!=')'){
		char sig = st.pop();
		if(sig=='+'){
			res+=(int)st.pop();
		}else{
			res-=(int)st.pop();
		}
	}
	return res;
}

主函数:

public int calculator(String s){
	s = "("+s+")";//使calInStack能计算全部的
	int p=0;//记录这个数字是整个数的第几位
	int sum = 0;//记录整个数
	Stack<Object> st = new Stack<>();
	for(int i=s.length()-1;i>=0;i--){
		//从后往前遍历
		char ch = s.charAt(i);
		if(Character.isDigit(ch)){
			sum += (int)Math.pow(10,p)*(ch-'0');
			p++;
		}else if(ch!=' '){
			//+或-或括号
			//查看p是否不为0,说明之前正在拼数,把数放入栈
			if(p!=0){
				st.push(sum);
				sum=0;
				p=0;
			}
			if(ch=='('){
				//遇到左括号,需要计算栈中第一个右括号之间的结果
				int res = calInStack(st);
				st.pop();//右括号出栈
				st.push(res);//结算当前括号并入栈
			}else{
				//+或-
				st.push(ch);
			}
		}
		return calInStack(st);
	}

5 队列实现栈

LeetCode225. 队列实现栈
考虑用两个队列,队列A用来存储,队列B用来倒腾
每次有新元素入栈时,先放到B,然后把A中的元素出列并放入B。然后AB互换

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值