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

原题来自力扣第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
    评论
好的,关于力扣刷题C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷题中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷题中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷题中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷题中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷题中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷题中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷题中,使用 string 可以方便地处理字符串相关的问题。 9. 注意边界条件:在力扣刷题中,边界条件往往是解决问题的关键。需要仔细分析题目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷题中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值