力扣刷题 之 表示数字的最少运算符

原题来自力扣第964题

这里复制粘贴了原题:

// 给定一个正整数 x,我们将会写出一个表达式,其中每个运算符可以是加、减、乘、除

//(+,-,*,或是/)之一。
// 必须遵循以下规则: 
// 除运算符(/)返回有理数。
// 任何地方都没有括号。
// 我们使用通常的操作顺序:乘法和除法发生在加法和减法之前。
// 例如 (x=3,target=19) 19=3*3+3*3+3/3; 返回 5 

看到只有很少题解,而且题目标注困难,我就莫名想整点活,给c区加一份题解,于是我开始构思

一开始读这道题,大致就是用pow(x,i)计算阶乘,用乘法逼近。

考虑到这道题还可以用减法,那就需要分偏大和偏小来考虑。

余下的步骤只需要对偏移的数进行递归就可以了。

while(pow(x,i)<target)  // 计算出阶乘数,作为二叉树的分支 
{
	++i;
}

如此一来就可以根据值的偏大、偏小、正好相等分类讨论。

这是正好相等的情况,比较简单:

if(pow(x,i)==target)
{
	return i-1;   // 直接返回阶数减一作为运算符的个数
}

对于偏大 的情况,考虑到数据的溢出,我反手一个long long,算是打不过就加入:

这里也附上对递归数据的调整,由于while循环的特性,这里取 i 和 i-1 作为指数调整。

如果数据过于偏大,防止陷入死循环,这里需要舍弃对较大值的递归,只计算较小那一支,舍弃的条件就是当调整之后的较大值 m 还要大于 原数据。

long long m=pow(x,i)-target;   // 防止数据越界 
long long n=target-pow(x,i-1); // 较小分支 
if(m>=target)         // 毕竟 n 不会超,那就讨论 m 吧 
{
	res=i-1+leastOpsExpressTarget(x,n);   // 超了就只递归 n  
}

 要是都符合递归的条件,那就顺理成章递归了

else
{
    // 合理的二叉递归,往后运算 
	res=fmin(i+leastOpsExpressTarget(x,m),i-1+leastOpsExpressTarget(x,n));
}

 各种数据都递归完毕了,需要讨论当 x<target 的情况了

要是严格等于的话:直接返回零就好了,不需要运算符(加号计算附带在递归中)

要是严格小于,则需要对区间[0,x]进行二分讨论,如下:

f(target<x)
{
    // 从 x 中间分段,左端用 1 累加,右端用 x- 若干个 1 
	if ((2 * target - 1)<(2 * (x - target)))  
	{
		return 2 * target - 1;
	}
	else 
	{
		return 2 * (x - target);
	}
}

到这里也就完成所有的思路以及细节的推导,算是对我整个做题过程的回顾这里附上完整的代码

如有错误,望大佬们指正。

int leastOpsExpressTarget(int x, int target)
{
    int res=0;
	if(target<x)
	{
		if ((2 * target - 1)<(2 * (x - target)))  // 从 x 中间分段,左端用 1 累加,右端用 x- 若干个 1 
		{
			return 2 * target - 1;
		}
		else 
		{
			return 2 * (x - target);
		}
	}
	else if(target==x)  // 直接返回那一个数,无需运算符 
	{
		return 0;
	}
	else
	{
		int i=1;
		while(pow(x,i)<target)  // 计算出阶乘数,作为二叉树的分支 
		{
			++i;
			if(pow(x,i)==target)
			{
				return i-1;
			}
		}
		long long m=pow(x,i)-target;   // 防止数据越界 
		long long n=target-pow(x,i-1); // 较小分支 
		if(m>=target)         // 毕竟 n 不会超,那就讨论 m 吧 
		{
			res=i-1+leastOpsExpressTarget(x,n);   // 超了就只递归 n  
		}
		else
		{
			res=fmin(i+leastOpsExpressTarget(x,m),i-1+leastOpsExpressTarget(x,n));  // 合理的二叉递归,往后运算 
		}
	}
	return res;
}

这里附加一下提交记录:

也是第一次在困难题拿到双百AC的记录,比较激动

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值