LeetCode 754 Reach a Number

题意:出发点位于数轴上的原点,对于第n步,可选择向左或是向右移动n个单位,求到达target的最小步数。

思考:

最开始没有什么想法,由于数据区间直接覆盖整个int类型,bfs什么的肯定不可能;

尝试贪心,但是没有任何数学依据。易证target具有对称性,因此不考虑起手往反方向跳的情况(贪心的想法),一直向右直到接近target;

因为第k步与第k+1步相差1,可以认为对于一段长度为1的路径,有cost(1)=2;

那么如果现在距离target为d,答案是否就是2*d呢?

很容易想到反例,不过解决这个问题似乎只要多跳一步然后看看两个2d和2d'哪个更小就行了。

尝试着交了一发,结果n=4就不行了:

  • -1+2+3=4,ans=3
  • 1+2-3+4=4,ans=4

区别在于第一步,答案是后跳的,因此贪心一定是错误的。

很容易将原问题转化为数学问题,一个等式,把1,2,3,...,n和target放进去,求最小的n能让等式成立。

高中的时候似乎有见过类似的东西,但是年代过于久远,也许数学竞赛的同学能够很快找到解决方法吧。

现在考虑整个流程:

  1. 0+1=1
  2. 1+2=3
  3. 3+3=6
  4. ...

 

  1. 0-1=-1
  2. -1+2=1
  3. 1+3=4√

我们可以发现寻找正解是需要在某些步骤进行逆运算的,而一次逆运算产生的差值与正运算相比为2n,也就是说我们可以通过将贪心结果减去一些2n对答案进行修正。由于n是递增的(包含了连续的数字),不需要考虑修正产生的越界问题以及不足以修正的问题。

于是,对于贪心后结果position与target差值为偶数的情况,我们通过修改运算符号即可得到正解,而此时步数不用改变;

对于奇数的情况,则取决于当前的n值,我们想要做的是将当前的奇数转化为偶数,那么当前n值是奇数的话,只需要再走一步,就得到了上述情况,也就是ans+=1;

当前n为偶数,则无法改变position与target差值的奇偶性,此时需要多走两步,即ans+=2;

因为此前我们采用贪心的策略,默认为到达target的最短路径不会存在其它最优解,大概可以证明上述算法的正确性..

以下代码部分,不过最后的奇偶部分为了方便好看并没有做成+1+2这些形式,最好按自己的理解完成代码编写:

class Solution {
public:
    int reachNumber(int target) {
        int ans = 0;
        if (target < 0) target *= -1;
        if (target == 0) return ans;
        int pos = 0;
        while(pos < target){
            ++ans;
            pos += ans;
        }//O(sqrt(n)), for more powerful data, please do solve the formula to get the answer
        if (pos > target){
            int delta = pos - target;
            if (delta % 2 == 1){
                if (ans % 2 == 0)
                    ++ans;
                else ans += 2;
            }
        }
        return ans;
    }
};

 

LeetCode是一个面向编程准备面试的在线平台,它提供了各种编程题目来帮助开发人员提高算法和数据结构的能力。下面是一个使用Java进行LeetCode刷题的指南: 1. 熟悉题库:首先,你需要熟悉LeetCode的题库。了解各种类型的题目,比如数组、字符串、链表、树等等,并了解它们对应的解决方法。 2. 制定计划:根据自己的时间和能力安排一个刷题计划,每天或每周刷一定数量的题目。有计划地刷题可以保证你的学习进度。 3. 注重基础:LeetCode高效的算法和数据结构知识,所以确保你掌握了一些基本的数据结构和算法,比如数组、链表、栈、队列、二叉树、图等等。 4. 解题过程:当你开始解题时,首先仔细阅读题目描述,并理解问题的要。然后分析问题,尽量找到一种简单而高效的解决方案。 5. 编码实现:在理解和分析问题之后,使用Java编写代码来解决问题。编写简洁、高效的代码可以提高你的编码能力。 6. 测试和优化:编写测试用例来验证你的代码是否正确,并分析你的代码的时间复杂度和空间复杂度。根据测试结果,进行代码优化以提高性能。 7. 学习他人的解决方案:LeetCode上有很多高手,他们在解决问题时可能采用了一些巧妙的解决方案。阅读和学习他们的代码可以帮助你提高自己的解题能力。 8. 多实践,多思考:不仅仅完成题目,还需要总结经验和教训。多思考为什么这个解决方案是高效的,以及如何在其他类似问题上应用相同的思路。 通过遵循这个LeetCode刷题指南,你可以提高自己的算法和数据结构的能力,为面试做好准备。刷题不仅仅是为了通过面试,更是提升自己的编程技能和思维能力的一种训练。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值