Frog Cross River - 改进二手数据结构

时间:2017-03-11 18:22:05

标签: java arrays algorithm

我试图通过贪婪来做这件事:

一只小青蛙想要到达河的另一边。青蛙目前位于0号位置,想要到达位置X.树叶从树上掉落到河面上。

给出一个非空零索引数组A,由表示落叶的N个整数组成。 A [K]表示一片叶子在时间K下降的位置,以分钟为单位测量。

目标是找到青蛙可以跳到河的另一边的最早时间。只有当叶子出现在从1到X的河对岸的每个位置时,青蛙才能穿过。

写一个函数:

class Solution { public int solution(int X, int[] A); }

给定一个由N个整数和整数X组成的非空零索引数组A,返回青蛙可以跳到河的另一边的最早时间。

如果青蛙永远不能跳到河的另一边,那么该函数应该返回-1。

我的解决方案

public int solution(int X, int[] A) {

        int[] vDestT = new int[A.length];
        int j = 0;
        // find times where X is visited
        // sort the array vDestT increasing order
        for (int i = 0; i < A.length; i++) {
            if (A[i] == X && i > X - 1) {
                // put times  corresponding to requested destination X in vDestT in an increasing order
                if (j > 0 && i < vDestT[j - 1]) {
                    int temp = vDestT[j - 1];
                    vDestT[j - 1] = i;
                    vDestT[j] = temp;
                } else
                    vDestT[j] = i;
                j++;
            }
        }

        int k = 0;
        while (k < vDestT.length) {
            int remainP = X - 1;
            int remainT = vDestT[k] - 1;
            // check A[0..X-1]
            while (remainT >= remainP) {
                if (A[remainT] < X) {
                    remainP--;
                }
                if (remainP == 0)
                    return vDestT[k];
                remainT--;
            }
            if (remainT < remainP) {
                k++;
                continue;
            }

        }
        return -1;

    }

嗯,这是第一个出现在我脑海中的解决方案(获得18/100分)并希望改进它,所以我有一些问题: - 我应该用哪种结构替换 vDestT

- 我错过了什么条件(除了if(A.length<X) and if (A.length == 1 && X==1))?

修改 我以为我必须找到A [i] = X的所有时间,将&#34; i&#34; s放在一个排序的数组递增顺序中。从我命名为vDestT的那个数组的第一个元素开始,看看我是否可以在那之前得到所有的X-1位置,如果没有检查第二次A [i] = X. =&gt;一个非常复杂的方法,我不知道为什么我确信我应该得到A [i] = X的所有时间并对它们进行排序以便找到最早的时间。

3 个答案:

答案 0 :(得分:3)

无需每个位置存储所有时间,然后对它们进行排序,因为您只对第一个感兴趣。此外,输入是按时间顺序排列的,因此您可能不需要一直检查到最后。

  • 创建一个能够存储X布尔值的数据结构,并将它们设置为false。
  • 创建一个计数器变量并将其设置为零。
  • 迭代A,并且每次i,如果位置A [i]的布尔值为假,则将其设置为true并递增计数器。
  • 一旦计数器等于X,所有位置都为真,时间i就是你的答案。
  • 如果在A的末尾,计数器小于X,则某些位置保持为空。

这样,您只需对输入进行一次迭代,并在X到N步骤中找到答案,即线性时间复杂度。

答案 1 :(得分:2)

你有一个数组A,它显然是一个按时间排序的元组(时间,位置)的集合。 填充所有索引在0和X之间的Set,并以方便的时间升序扫描Array,从集合中减去所看到的任何元素。当集合为空时,叶子的路径就完成了。你达到的时间点是最早可能的。 这需要线性时间和线性额外空间。

答案 2 :(得分:1)

由于此问题至少暂时标记为,因此我认为可能对基于Prolog的解决方案感兴趣。请注意,使用适合约束的包,此方法对于基于Java的解决方案也可能有用!

我正在使用Prolog来说明总体思路:我将使用约束变量来跟踪 water 仍在流动的指数,即没有(还)被叶子覆盖。将变量的域视为代表河流的未覆盖的点。

最初,变量的域是整数1,2,3 ......,即所有整数I∈[1,∞)。我们称之为变量Water

假设对整数有适当的约束,我可以在Prolog中表达初始域:

Water in 1..sup

这意味着,最初,所有索引尚未涵盖

我可以通过从变量的域中删除其索引来表明某个地点已被覆盖。

例如:

?- Water in 1..sup,
   Water #\= 3,
   Water #\= 7.

这使用了不平等约束,声明Water 不能再值3和7,因此我们将这些点视为覆盖通过叶子。对于上述查询,Prolog回答:

Water in 1..2\/4..6\/8..sup.

这只是一种更紧凑的方式来陈述完全相同的事情。

请注意,此类操作的时间复杂度取决于您的Prolog系统。例如,当从域中删除内部点时,GNU Prolog使用 bitvector 表示。这使得删除单个元素(摊销) O(1)操作!

现在仍然是系统地应用这种不平等约束,对于我们所有的位置,同时跟踪当前的指数。

解决方案可能如下所示:

minutes_to_x(Leaves, X, Min) :-
        Water in 1..sup,
        to_x(Leaves, X, Water, 1, Min).

to_x([], _, _, _, -1).
to_x([L|Ls], X, Water, Index0, Min) :-
        Water #\= L,
        (   fd_inf(Water, Inf), Inf #> X ->
            Min #= Index0
        ;   Index #= Index0 + 1,
            to_x(Ls, X, Water, Index, Min)
        ).

示例查询和答案:

?- minutes_to_x([1,3,2], 1, Min).
Min = 1.

?- minutes_to_x([1,3,2], 2, Min).
Min = 3.

?- minutes_to_x([1,3,2], 3, Min).
Min = 3.

?- minutes_to_x([1,3,2], 4, Min).
Min = -1.

这是一个关系,而不是一个函数,因此我们使用最后一个参数来保存分钟的数量。

只要X infimum 大于Water,青蛙就可以移动到X位置,因为这意味着从1到1的所有点都会叶子<{1}} 涵盖