【问题标题】:Programming test on algorithms? [closed]算法编程测试? [关闭]
【发布时间】:2016-11-22 16:14:20
【问题描述】:

我在一家 IT 公司的编程测试中被问到这个问题。 我会尽力解释的。

问题如下:

给定一个在原点 (0,0) 的 Ant,它只在给定的路径数组上顺时针方向移动(只需要右转)。例如,如果路径数组是 {2,3,4,5,7},蚂蚁向左移动 2 个单位,然后向下移动 3 个单位,然后向右移动 4 个单位,然后向上移动 5 个单位,然后向左移动 7 个单位,依此类推等等。

所以编写一个代码来显示蚂蚁的最终位置(坐标)并说明蚂蚁是否与它的路径相交,格式如下:

蚂蚁:(x1,y1) :(是/否)

例如: (1) 数组={1,6,3,5,4} 输出:蚂蚁:(2,-1):是的

以图形方式显示

         (0, 0)__(1,0)
                    |
 (-2,-1)   __ __ __ __(2,-1)
        |           |
        |           |
        |           |
        |           |
        |           |
  (-2,-6)  __ __ __    (1,-6)

这里蚂蚁在 (1,-1) 处与它的路径相交

(2) 数组={2,2,2,1} 输出:蚂蚁:(0,-1):否

以图形方式显示

(0, 0)__ __(2,0)
 .(0,-1)    |
 |          |
(0,-2)__ __(2,-2)

这里蚂蚁没有与它的路径相交。

我写了一个代码来找到最终位置:

public class Ant {

    static void findAnt(int arr[])
    {
        int count = 0;
        int x=0,y=0;
        for(int element: arr){
            if(count>3)
                count = 0;

            switch(count++){

            case 0: x=x+element;
                    break;
            case 1: y=y-element;
                    break;
            case 2: x=x-element;
                    break;
            case 3: y=y+element;
                    break;

            }
        }
        System.out.println("Ant: "+x+" "+y);
    }
    public static void main(String[] args)
    {
        int arr[] = new int[]{2,2,2,1};
        findAnt(arr);
    }


}

但是我无法设计一种算法来显示蚂蚁是否相交。 请指教。

【问题讨论】:

  • 创建一个布尔数组,将其全部填充为 false,然后当蚂蚁在该图块上“行走”时,将其翻转为 true。然后当你有蚂蚁的最终位置时,检查那个图块是否已经是真的,如果是,那么它之前就已经存在了。
  • 谢谢@user123,如果你能详细说明你的解决方案,那会很有帮助吗?
  • 创建一个boolean[][] gameBoard,大小可以设为n * n,初始化为false。然后开始循环遍历你的动作数组,当蚂蚁沿着每个索引行走时,将值翻转为true(它一直在那里)。然后,当您到达移动数组中的最后一个索引时,您检查该图块是否已经是true,如果是,那么您已经在那里了。
  • @user123: 如果蚂蚁的路径与它自己在一个不是蚂蚁最后访问的瓦片上相交怎么办? :)
  • 另一种方法是创建一大堆线(蚂蚁起点到终点),然后进行点线测试,其中点是蚂蚁对所有线的结束位置行。

标签: java algorithm array-algorithms


【解决方案1】:

如果arr[1] <= arr[3],它将水平相交,如果arr[0] <= arr[2],它将垂直相交,您只需要检查这些位置。

for (int i = 0; i < arr.length; i++){
     if (i == arr.length-2)
         return false;//prevents indexoutofbounds
     if (arr[i] <= arr[i+2])
         return true;//intersects
}

这应该检查 p0 是否小于 p2、p1、是否小于 p3、p2 是否小于 p4,等等。

boolean intersect = false;



    for (int i = 0; i < arr.length; i++){
            if (arr[i] == arr[arr.length-2]){//i changed this
                intersect = false;//prevents indexoutofbounds
                break;

            }
            if (arr[i] <= arr[i+2])
                intersect =  true;//intersects
                break;
       }

然后打印出 intersect

【讨论】:

  • 在你的代码中,当你发现真或假时,你需要跳出循环,因为你不能使用返回
  • 恐怕它不起作用。对于 array={2,2,2,1},即使蚂蚁没有相交,它也会输出 true。
  • 我弄错了,我会告诉你我是如何实现的,
  • 哦,我知道为什么,把
  • 虽然它适用于某些测试用例,但它并不适用于所有测试用例,我考虑了一个 array={5,6,3,5,4} 并且执行它时输出结果是假的。
【解决方案2】:

一种不在内存中保留网格的解决方案是在内存中保留一组访问过的位置。这样做的好处是不需要提前知道蚂蚁潜在路径的边界。它比网格占用更多或更少的内存,取决于网格的大小,以及蚂蚁的旅程长度。

public class VisitedTileLog {

      Set visitedTiles = new HashSet<Coordinates>();
      boolean hasIntersected = false;

      public void logVisit(Coordinates c) {
          if(! visitedTiles.add(c)) {
              hasIntersected = true;
          }
      }

      public boolean hasIntersected() {
          return hasIntersected;
      }
}

当然,你需要一个 Coordinates 类和 equals()hashCode()

public class Coordinates {
     private int x,y;

     public Coordinates(int x, int y) {
        this.x = x;
        this.y = y;
     }

     public boolean equals(Object o) {
        // Let your IDE write this, or read up on best practice.
     }

     public int hashCode() {
        // Let your IDE write this, or read up on best practice.
     }

     // Examples of other methods this might have...
     public int getX() { ... }
     public int getY() { ... }
     public Coordinates move(int distance, Direction direction);
}

现在你可以带你的蚂蚁去散步,每次它移动时,更新hasIntersected

 VisitedTileLog log = new VisitedTileLog();
 for(int distance : distances) {
      ...
      log.logVisit(...);
      ...
 }

可以使用记录整个步骤的便捷方法来增强此类 - logVisit(Coordinates from, Coordinates to)logVisit(Coordinates start, int distance, CompassPoint direction)

根据面试官的不同,这样的解决方案可能会让你因面向对象而获得额外的荣誉。事实上,如果它还维护一个currentPosition 字段,则可以增强这个类来解决整个问题。

【讨论】:

  • 你还在暴力破解。由于蚂蚁只进行相同的转弯,因此它所走的步骤很快就变得无关紧要(与旧路段相交的路径必须与新路段相交)。在最坏的情况下,只需要跟踪最后的 5 个片段。
  • @user58697 最后一句话是需要做的关键观察。只有最后 5 个段必须被跟踪。恭喜你解决了这个难题。有了这些知识,线性时间解决方案应该很容易实现......
  • 这是一个公平的观点,我所描述的方法可以在它们的有用性过去之后增强为老化对数正方形。它还可以存储线列表而不是正方形,并以更复杂的方式计算交叉点。有无限的时间,我会从这个蛮力解决方案开始,编写单元测试,然后将其改进为更智能。
  • @slim 嘿!你能描述一下坐标类的方法以便更好地理解吗?谢谢。
  • @slim 我是说你应该保留一个固定大小的队列 (5)。在创建新段时,检查元素 0、1、2、3(您将始终与元素编号 4 相交)。然后删除第一个元素并将新创建的段放在队列的末尾。这将使您对路径中的每个点执行恒定数量的操作(创建段 + 4 次检查)而不是 O(n) 次检查(检查 所有 其他段)
【解决方案3】:

实现这一点的一种方法是在每次移动时画线以供参考。并在每次移动之前检查它是否遇到已经绘制的相同坐标。下面是这种方法的代码。您绝对可以对其进行微调,但这是解决它的一种方法。

步骤:
创建 Coordinate 类型以存储坐标。
创建可以容纳的Antcurrent coordinate:这将随时保存 Ant Current 坐标
Direction to Move next:右、左、上或下
跟踪traversed coordinate的数据集
保存所有coordinates that are revisited的数据结构

现在ant 的一举一动,它都知道下一步该往哪个方向移动。并且在每次移动中,我们绘制当前坐标和终点之间的所有坐标,并将它们存储在遍历坐标set中。如果有命中,我们将其存储在相交坐标set 中。

最后,ant 中的current coordinate 给了我们最终的coordinate,如果相交的setnot empty.,则线交叉

这是长代码,我认为它工作正常。

public class PathCross {

public static void main(String[] args) {

    int[] movementArray = { 2, 2, 2, 1 };// {1,6,3,5,4};
    PathCross driver = new PathCross();
    Ant ant = driver.new Ant();

    for (int i : movementArray) {
        ant.move(i);
    }

    System.out.println("Ant: (" + ant.currentCoordinate.getX() + "," + ant.getCurrentCoordinate().getY() + ") :"
            + !ant.getIntersectingCoordinates().isEmpty());
}

class Ant {

    Coordinate currentCoordinate = new Coordinate(0, 0);
    Direction nextDirection = Direction.RIGHT;

    Set<Coordinate> intersectingCoordinates = new HashSet<>();

    Set<Coordinate> traversedCoordinateSet = new HashSet<>();

    public Ant() {
        traversedCoordinateSet.add(new Coordinate(0, 0));
    }

    public Coordinate getCurrentCoordinate() {
        return currentCoordinate;
    }

    public void setCurrentCoordinate(Coordinate currentCoordinate) {
        this.currentCoordinate = currentCoordinate;
    }

    public Direction getNextDirection() {
        return nextDirection;
    }

    public void setNextDirection(Direction nextDirection) {
        this.nextDirection = nextDirection;
    }



    public Set<Coordinate> getIntersectingCoordinates() {
        return intersectingCoordinates;
    }

    public void setIntersectingCoordinates(Set<Coordinate> intersectingCoordinates) {
        this.intersectingCoordinates = intersectingCoordinates;
    }

    public Set<Coordinate> getTraversedCoordinateSet() {
        return traversedCoordinateSet;
    }

    public void setTraversedCoordinateSet(Set<Coordinate> traversedCoordinateSet) {
        this.traversedCoordinateSet = traversedCoordinateSet;
    }

    public void move(int distance) {
        Coordinate newCoordinate = null;
        switch (nextDirection) {

        case RIGHT:
            newCoordinate = new Coordinate(currentCoordinate.getX() + distance, currentCoordinate.getY());
            for (int i = currentCoordinate.getX() + 1; i <= (currentCoordinate.getX() + distance); i++) {
                if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) {
                    intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
                }

            }
            nextDirection = Direction.DOWN;
            break;

        case DOWN:
            newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() - distance);
            for (int i = currentCoordinate.getY() - 1; i >= (currentCoordinate.getY() - distance); i--) {
                if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) {
                    intersectingCoordinates.add(new Coordinate(currentCoordinate.getX(), i));
                }
            }
            nextDirection = Direction.LEFT;
            break;

        case LEFT:
            newCoordinate = new Coordinate(currentCoordinate.getX() - distance, currentCoordinate.getY());
            for (int i = currentCoordinate.getX() - 1; i >= (currentCoordinate.getX() - distance); i--) {
                if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) {
                    intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
                }
            }
            nextDirection = Direction.UP;
            break;

        case UP:
            newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() + distance);
            for (int i = currentCoordinate.getY() + 1; i <= (currentCoordinate.getY() + distance); i++) {
                if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) {
                    intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
                }
            }
            nextDirection = Direction.RIGHT;
            break;

        default:
            System.err.println("ERRor");

        }

        this.currentCoordinate = newCoordinate;

    }

}

enum Direction {
    LEFT, DOWN, RIGHT, UP;
}

class Coordinate {
    int x;
    int y;

    public Coordinate() {

    }

    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getOuterType().hashCode();
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Coordinate other = (Coordinate) obj;
        if (!getOuterType().equals(other.getOuterType()))
            return false;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }

    private PathCross getOuterType() {
        return PathCross.this;
    }

    @Override
    public String toString() {
        return "x=" + x + ", y=" + y;
    }

}

}

【讨论】:

    【解决方案4】:

    这个问题很难找出它是否与之前的路径相交。我创建了一个布尔值来记录它是否增加了圆圈。如果它一直在增加,它不会与之前的路径相交。如果它变为减少,一旦它再次开始增加,它将与路径相交。否则不会与路径相交

    def ant(arr):
        length = len(arr)
        x = sum(arr[::4]) - sum(arr[2:][::4])
        y = sum(arr[3:][::4]) - sum(arr[1:][::4]) 
        if length < 4:
            return x, y, False
        t1, (t2, t3, t4) = 0, arr[:3]
        increase = (t2 < t4)
        for i in xrange(3, length):
            t5 = arr[i]
            if increase and t3 >= t5:
                if t1 + t5 - t3 < 0 or i+1 < length and arr[i+1] + t2 - t4 < 0:
                    increase = False
                elif i + 1 < length:
                    return x, y, True
    
            elif not increase and t3 <= t5:
                return x, y, True
            t1, t2, t3, t4 = t2, t3, t4, t5
        return x, y, False
    

    【讨论】:

      猜你喜欢
      • 2021-06-23
      • 2011-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      相关资源
      最近更新 更多