到达终点数字

这篇博客探讨了一个算法问题,即在无限长的数轴上从0开始,通过有限次向左或向右移动到达目标位置。文章介绍了利用二分搜索策略找到最小移动次数的方法,考虑了移动总步数的奇偶性和差值,确保最终能够精确到达目标。代码给出了Python和Java两种实现。
摘要由CSDN通过智能技术生成

到达终点数字

在一根无限长的数轴上,你站在0的位置。终点在target的位置。你可以做一些数量的移动 numMoves :

  • 每次你可以选择向左或向右移动。
  • 第 i 次移动(从 i == 1 开始,到 i == numMoves ),在选择的方向上走 i 步。
    给定整数 target ,返回 到达目标所需的 最小 移动次数(即最小 numMoves ) 。

思路

  • 假设第1…, i 次均向右移动,那么移动的步数分别为1,2,3,…,i步;
  • 假设第1…, i 次均向左移动,那么移动的步数分别为-1,-2,-3,…,-i步;
  • 因此第1…, i 次的某次选择向左或向右移动,移动的总步数的差值分别为-2,-4,-6,…,-2i步;
  • 假设移动到终点target位置,最多需要target步,那么可以根据二分迭代搜索需要的最小移动次数;
    • 搜索起始边界L,R分别为0,target,对应的每次搜索的中间位置m=(L+R)/ 2, 搜索停止条件L > R,定义到达target位置附近所需要的移动次数为 near;
    • 从1一直加到m的和,设为sum(m);如果sum(m) >= target,则更新near = m,直到停止搜索为止;
    • 如果此时的sum(near) 恰好等于target,则near就是要找的最小移动次数;
    • 如果此时的sun(near) > target,也即移动的总步数超出了target,建设此时超出的步数为diff = sun(near) - target
    • 如果diff为偶数,也即需要之前的某一步向左移动即可满足(参考第三条差值),那么可以直接返回near。
    • 如果diff为奇数,就需要near再向右移动,因为无论如何调整之前的某一步方向,不会改变sum(near)的奇偶性,也就不会改变diff的奇偶性,也就到不了target位置;
    • 那near再向右移动多少步呢?好问题。观察一下sum(m)的数值,【1,3,6,10,15,21,28,36】奇奇偶偶奇奇偶偶 交替出现,因此最多再移动两步就可以改变sum(near)的奇偶性,也即改变了diff的奇偶性。

代码

Python

class Solution:
    def sum(self, m):
        return int((m * (m+1))/2)

    def reachNumber(self, target: int) -> int:
    
        target = abs(target)
        l, r = 0, target
        m, near = 0, 0
        while l <= r:
            m = int((l + r)/2)
            if self.sum(m) >= target:
                near = m
                r = m - 1
            else:
                l = m + 1
        if self.sum(near) == target:
            return near
        
        # 差值为奇数  sum和规律 奇奇偶偶奇奇偶偶 交替,因此循环两次
        if ((self.sum(near) - target) & 1) == 1:
            near += 1
        
        if ((self.sum(near) - target) & 1) == 1:
            near += 1

        return near

Java

public class ReachNumber {

	public static int reachNumber(long target) {
		if (target == 0) {
			return 0;
		}
        target = Math.abs(target);
		long l = 0;
		long r = target;
		long m = 0;
		long near = 0;
		while (l <= r) {
			m = (l + r) / 2;
			if (sum(m) >= target) {
				near = m;
				r = m - 1;
			} else {
				l = m + 1;
			}
		}
		if (sum(near) == target) {
			return (int)near;
		}
		if (((sum(near) - target) & 1) == 1) {
			near++;
		}
		if (((sum(near) - target) & 1) == 1) {
			near++;
		}
		return (int)near;
	}

	public static long sum(long n) {
		return (n * (n + 1)) / 2;
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NLP_wendi

谢谢您的支持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值