首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java中的SkylineProblem

Java中的SkylineProblem
EN

Code Review用户
提问于 2021-06-02 04:46:49
回答 1查看 101关注 0票数 3

摘自leetcode.com:

从远处看,城市的天际线是由城市内所有建筑物形成的轮廓的外部轮廓。鉴于所有建筑物的位置和高度,返回由这些建筑物共同形成的天际线。...

请检查这段代码。我最感兴趣的是关于OOP原理的反馈(坚实、可读性等)。其次是对表演最感兴趣。

类解决方案

代码语言:javascript
复制
public class Solution {

    public static void main(String[] args) {
        final int[][] input = {{2,9,10},{3,7,15},{5,12,12},{15,20,10},{19,24,8}};
        Solution solution = new Solution();
        System.out.println("amount : "+solution.getSkyline(input));
    }

    //this crude method is a HARD REQUIREMENT and may not be changed!
    public List<List<Integer>> getSkyline(int[][] buildings) {
        SkyLineConverter skyLineConverter = new SkyLineConverter();
        SkyLine skyLine = skyLineConverter.convert(buildings);
        Set<Edge> edges = skyLine.getEdges();
        return sortList(edges);
    }

    private List<List<Integer>> sortList(Set<Edge> edges) {
        List<List<Integer>> result = new ArrayList<>();
        List<Edge> list = new ArrayList<>(edges);
        list.sort(Comparator.comparingInt(o -> o.x));
        for(Edge edge: list){
            List<Integer> intList = new ArrayList<>();
            intList.add(edge.x);
            intList.add(edge.height);
            result.add(intList);
        }
        return result;
    }
}

类SkyLineConverter

代码语言:javascript
复制
public class SkyLineConverter {
    public SkyLine convert(int[][] raw) {
        BuildingConverter buildingConverter = new BuildingConverter();
        List<Building> buildings = buildingConverter.convert(raw);
        return new SkyLine(buildings);
    }
}

类建筑

代码语言:javascript
复制
public class Building {

    public final int x;
    public final int width;
    public final int height;

    public Building(int x, int width, int height) {
        this.x = x;
        this.width = width;
        this.height = height;
    }

}

类BuildingConverter

代码语言:javascript
复制
public class BuildingConverter {

    private static final int FROM_INDEX = 0;
    private static final int TO_INDEX = 1;
    private static final int HEIGHT_INDEX = 2;

    public List<Building> convert(int[][] raw) {
        List<Building> buildings = new ArrayList<>();
        for (int[] buildingRaw: raw){
            int x = buildingRaw[FROM_INDEX];
            int width = buildingRaw[TO_INDEX] - buildingRaw[FROM_INDEX];
            int height = buildingRaw[HEIGHT_INDEX];
            buildings.add(new Building(x,width,height));
        }
        return buildings;
    }
}

类天际线

代码语言:javascript
复制
public class SkyLine {

    private final int width;
    private final Set<Edge> edges = new HashSet<>();
    private final List<Building> buildings;

    public SkyLine(List<Building> buildings) {
        this.buildings = buildings;
        Building mostRight = findMostRight(buildings);
        width = mostRight.x + mostRight.width;
        addEdge();
    }

    private void addEdge() {
        buildings.forEach(b -> {
            addEdge(b.x);
            addEdge(b.x + b.width);
        });
        edges.add(new Edge(width, 0));
    }

    private void addEdge(int x) {
        int skyline = getSkyLine(x);
        int previous = x == 0 ? 0 : getSkyLine(x - 1);
        if (previous < skyline || previous > skyline) {
            edges.add(new Edge(x, skyline));
        }
    }

    private int getSkyLine(int x) {
        List<Building> aroundThisPoint = buildings.stream().
                filter(b -> b.x <= x && b.x + b.width > x).
                collect(Collectors.toList());
        return aroundThisPoint.stream().mapToInt(b -> b.height).max().orElse(0);
    }

    private Building findMostRight(List<Building> buildings) {
        Optional<Building> mostRight = buildings.stream().reduce((a, b) ->
                a.x > b.x ? a : b);
        //noinspection OptionalGetWithoutIsPresent
        return mostRight.get();
    }

    public Set<Edge> getEdges() {
        return edges;

    }

}

类边缘

代码语言:javascript
复制
public class Edge {

    public final int x;
    public final int height;

    public Edge(int x, int height){
        this.x = x;
        this.height = height;
    }

}
EN

回答 1

Code Review用户

回答已采纳

发布于 2021-06-02 17:31:00

我注意到您在大部分代码中都使用了流库,所以我考虑在可能的情况下使用更少的代码行来提高可读性,因为在我看来其他部分都很好。在您的Solution类中,您有以下方法:

代码语言:javascript
复制
private List<List<Integer>> sortList(Set<Edge> edges) {
    List<List<Integer>> result = new ArrayList<>();
    List<Edge> list = new ArrayList<>(edges);
    list.sort(Comparator.comparingInt(o -> o.x));
    for(Edge edge: list){
       List<Integer> intList = new ArrayList<>();
       intList.add(edge.x);
       intList.add(edge.height);
       result.add(intList);
    }
    return result;
}

您可以将edges集与Stream#sortedStream#map组合起来直接迭代,从而避免了显式实例化列表的需要,如下所示:

代码语言:javascript
复制
private List<List<Integer>> sortList(Set<Edge> edges) {
        
   return edges.stream()
           .sorted(Comparator.comparingInt(edge -> edge.x))
           .map(edge -> List.of(edge.x, edge.height))
           .collect(Collectors.toList());        
}

在您的BuildingConverter类中,您有以下方法:

代码语言:javascript
复制
public List<Building> convert(int[][] raw) {
    List<Building> buildings = new ArrayList<>();
    for (int[] buildingRaw: raw){
        int x = buildingRaw[FROM_INDEX];
        int width = buildingRaw[TO_INDEX] - buildingRaw[FROM_INDEX];
        int height = buildingRaw[HEIGHT_INDEX];
        buildings.add(new Building(x,width,height));
    }
    return buildings;
}

您的int[][] raw 2d数组的每一行都有可能流到Arrays#streamStream#map,以获得相同的预期结果如下所示:

代码语言:javascript
复制
public List<Building> convert(int[][] raw) {

    return Arrays.stream(raw)
           .map(arr -> new Building(arr[FROM_INDEX], 
                                    arr[TO_INDEX] - arr[FROM_INDEX], 
                                    arr[HEIGHT_INDEX]))
           .collect(Collectors.toList());
}

在类SkyLine中,可以简化以下两个方法:

代码语言:javascript
复制
private int getSkyLine(int x) {
    List<Building> aroundThisPoint = buildings.stream().
           filter(b -> b.x <= x && b.x + b.width > x).
           collect(Collectors.toList());
    return aroundThisPoint.stream().mapToInt(b -> b.height).max().orElse(0);
}

private Building findMostRight(List<Building> buildings) {
    Optional<Building> mostRight = buildings.stream().reduce((a, b) ->
           a.x > b.x ? a : b);
    //noinspection OptionalGetWithoutIsPresent
    return mostRight.get();
}

在您的getSkyLine方法中,不需要实例化将要流的中间列表,您可以使用更简洁的方法组合代码行:

代码语言:javascript
复制
private int getSkyLine(int x) {
        
    return buildings.stream()
            .filter(b -> b.x <= x && b.x + b.width > x)
            .mapToInt(b -> b.height)
            .max()
            .orElse(0);
}

findMostRight方法可以使用Collections#max进行简化,如下所示:

代码语言:javascript
复制
private Building findMostRight(List<Building> buildings) {

    return Collections.max(buildings, Comparator.comparingInt(b -> b.x));
}
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/261533

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档