【刷题】最近刷的三道题目

【刷题】最新刷的3道题目

题目一

考虑你从家出发步行去往一处目的地,该目的地恰好离你整数单位步长(大于等于1)。
你只能朝向该目的地或者背向该目的地行走,而你行走的必须为单位步长的整数倍,且要求你第N次行走必须走N步。
请就给出目的地离你距离,判断你是否可以在有限步内到达该目的地。
如果可以到达的话,请计算到达目的地的最短总步数(不能到达则输出-1)

假设我们的目的地是s,我们需要走n步才能到达。

最理想的情况是,我们直接走n步,不需要回退就到达了。这个时候 s1 = 1+2+...+n 。

假设我们已经走了p-1步,如果直接走完p步,(1+...+p)-n = x,也就是会比目的地多x步。
如果 x 是偶数,这个时候只需要在x/2步的时候回退。因为 (1+...+x/2+...+p) - (1+...-x/2+...+p) = x.也就是 (1+...+p) - x= (1+...-x/2+...+p) = n;

如果 x 是奇数,假设 x = 2m+1 。 也就是 (1+...+p) - n = 2m+1 。
这个时候怎么办?
我们可以把它化成偶数的情况 (1+...+p) - (2m+1) = n -> (1+...-m+...+p) -(p+1)+p+2 = (1+...+p) - (2m+1) = n 。
也就是说如果是奇数的情况,我们不仅需要在m处回退,还要 p+1处回退,p+2处往前走。

这里求的是步数,
对于差值是偶数的情况,我们可以看到,不需要多走,只需要再中间的某一步回退;
对于差值是奇数的情况,我们可以看到是需要多走两步的。

我们用代码描述一下上面这些过程

private static int getStep(int n){
    int sum = 0;
    int step = 0;
    while(sum < n){
        step ++;
        sum += step;
    }
    if((sum-n)%2 == 1){
        step = step + 2;
    }
    return step;
}

题目二

序列找数
从非负整数序列 0, 1, 2, ..., n中给出包含其中n个数的子序列,请找出未出现在该子序列中的那个数。
输入描述:
输入为n+1个非负整数,用空格分开。
其中:首个数字为非负整数序列的最大值n,后面n个数字为子序列中包含的数字。
输出描述:
输出为1个数字,即未出现在子序列中的那个数。
例如:输入:3 3 0 1 输出: 2

一种很容易想到的思路是,使用标记的方式。先将n以下的自然数作为key写入map, value 就是出现的次数,然后再循环遍历输入队列,最后map中value为0的数就是没有出现的数。

用代码实现就如下所示:

private static int getOne(int n, int[] nums){
    Map<Integer, Integer> map = new HashMap<>(n+1);
    for(int i=0;i<=n;i++){
        map.put(i,0);
    }

    Arrays.stream(nums).forEach(x -> {
        int value = Optional.ofNullable(map.get(x)).orElse(0);
        map.put(x, ++value);
    });

    for(int i=0;i<=n;i++){
        if(map.get(i) == 0){
            return i;
        }
    }

    return -1;
}

题目三

题目描述
小喵喜欢在数轴上跑来跑去,假设它现在站在点n处,它只会3种走法,分别是:
1.数轴上向前走一步,即n=n+1
2.数轴上向后走一步,即n=n-1
3.数轴上使劲跳跃到当前点的两倍,即n=2*n
现在小喵在原点,即n=0,它想去点x处,快帮小喵算算最快的走法需要多少步?

假设小喵要到达x处,有下面几种情况:
如果x是偶数,有两种方法到达x处,
 一种是, 在到达 x/2 的地方,纵身一跃,跳到x处;
 一种是,在到达 x-1 的地方,往前走一步

如果x是奇数,有三种方法到达x处,
 一种是,在 (x+1)/2 的地方纵身一跃,跳到 x+1 处,然后后退一步
 一种是,在 (x-1)/2 的地方纵身一跃,跳到 x-1 处,然后前进一步
 一种是,在 x-1 的地方,往前走一步

从分析上看走到第 x 处的步数依赖之前的情况,我们可以想到动态规划

假设 step[i] 表示跳到 i 处需要的步数,根据上面的分析可以得出:

if(i%2 == 0){
    step[i] = Math.min(step[i/2] + 1, step[i-1] +1);
}else{
    int min = Math.min(step[(i+1)/2] + 2, step[(i-1)/2] + 2);
    step[i] = Math.min(min, step[i-1] + 1);
}

需要考虑一些边界情况:
如果到达点是0, 需要的步数是0;如果到大殿是1,需要的步数是1;

完整的代码如下:

    private static int getStep(int x){
        if(x < 0){
            x = -x;
        }

        if(x < 2 && x >= 0){
            return x;
        }
        //step[i] 表示走到i,小招喵需要最少的次数
        int[] step = new int[x+1];
        step[0] = 0;
        step[1] = 1;
        for(int i=2; i<=x; i++){
            if(i%2 == 0){
                step[i] = Math.min(step[i/2] + 1, step[i-1] +1);
            }else{
                int min = Math.min(step[(i+1)/2] + 2, step[(i-1)/2] + 2);
                step[i] = Math.min(min, step[i-1] + 1);
            }
        }

        return step[x];
    }
原文地址:https://www.cnblogs.com/catlkb/p/13909301.html