AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79599173
Accepted
Abhijit Sarkar
Abhijit Sarkar
Asked: 2025-04-30 04:34:21 +0800 CST2025-04-30 04:34:21 +0800 CST 2025-04-30 04:34:21 +0800 CST

Comportamento estranho do comparador PriorityQueue quando a ordem de classificação é obtida do hashmap

  • 772

Enquanto trabalhava no LeetCode 675 , me deparei com um comportamento estranho PriorityQueue Comparatorque não consigo explicar.

Para resumir, vou apresentar a essência da declaração do problema; os interessados ​​podem lê-la em detalhes no LeetCode.

Dada uma matriz mxn chamada forest, algumas células são designadas como trees. O desafio é encontrar o número mínimo de passos para visitar (cortar) todas as células da árvore, em ordem crescente de altura da árvore.

Para resolver isso, encontro todas as árvores e as ordeno em ordem crescente de altura. Em seguida, calculo a distância mínima de cada árvore até a próxima executando uma busca A* usando a função heurística:distance from source + Manhattan distance from the goal

O número mínimo de passos para cortar todas as árvores é a soma de todas as distâncias A*. Se em algum momento a busca A* não retornar um caminho, eu aborto.

class Solution {
  private final int[][] dx = new int[][] {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

  public int cutOffTree(List<List<Integer>> forest) {
    int[] curr = new int[] {0, 0};
    int dist = 0;

    for (int[] next : getTreesSortedByHeight(forest)) {
      int d = minDist(forest, curr, next);
      if (d < 0) {
        return -1;
      }
      curr = next;
      dist += d;
    }

    return dist;
  }

  private List<int[]> getTreesSortedByHeight(List<List<Integer>> forest) {
    List<int[]> trees = new ArrayList<>();
    for (int row = 0; row < forest.size(); row++) {
      for (int col = 0; col < forest.get(0).size(); col++) {
        if (forest.get(row).get(col) > 1) {
          trees.add(new int[] {row, col});
        }
      }
    }
    trees.sort(Comparator.comparingInt(a -> forest.get(a[0]).get(a[1])));
    return trees;
  }

  int minDist(List<List<Integer>> forest, int[] start, int[] goal) {
    int m = forest.size();
    int n = forest.get(0).size();
    Map<Integer, Integer> costs = new HashMap<>();
    costs.put(start[0] * n + start[1], manhattanDist(start[0], start[1], goal));
    // GOTCHA: Fetching the distance from the cost map using the coordinates doesn't work!
    Queue<int[]> heap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
    heap.offer(new int[] {0, 0, start[0], start[1]}); // [cost, distance, row, column]

    while (!heap.isEmpty()) {
      int[] curr = heap.poll();
      int dist = curr[1];
      int row = curr[2];
      int col = curr[3];

      if (row == goal[0] && col == goal[1]) {
        return dist;
      }
      for (int[] d : dx) {
        int r = row + d[0];
        int c = col + d[1];
        if (r >= 0 && r < m && c >= 0 && c < n && forest.get(r).get(c) > 0) {
          int cost = dist + 1 + manhattanDist(r, c, goal);
          if (cost < costs.getOrDefault(r * n + c, Integer.MAX_VALUE)) {
            costs.put(r * n + c, cost);
            heap.offer(new int[] {cost, dist + 1, r, c});
          }
        }
      }
    }
    return -1;
  }

  private int manhattanDist(int row, int col, int[] goal) {
    return Math.abs(goal[0] - row) + Math.abs(goal[1] - col);
  }
}

Observe que cada entrada de heap contém o custo heurístico . Logicamente, isso é desnecessário , pois a entrada também contém as coordenadas da célula (linha e coluna), com as quais podemos obter a distância do costsmapa da seguinte maneira:

Queue<int[]> heap = new PriorityQueue<>(Comparator.comparingInt(a -> costs.get(a[1] * n + a[2]);
  • Na ausência do custo, a entrada do heap consiste em [distância, linha, coluna].

Mas isso não funciona e falha em um dos casos de teste. O caso de teste é enorme, então não vejo sentido em colá-lo aqui, pois é improvável que alguém tenha tempo para depurá-lo.

O que eu gostaria de saber é o porquê dessa estranheza.

Editar: código completo adicionado conforme solicitado em um comentário.

java
  • 1 1 respostas
  • 78 Views

1 respostas

  • Voted
  1. Best Answer
    Louis Wasserman
    2025-04-30T06:18:05+08:002025-04-30T06:18:05+08:00

    PriorityQueuenão consegue lidar com isso se a ordem de seus elementos mudar enquanto eles ainda estiverem na fila, e seu comportamento for indefinido nesse cenário. Coisas muito estranhas podem acontecer, já que a propriedade heap dos elementos é silenciosamente quebrada, sem que haja como PriorityQueuesaber que isso aconteceu. Parece bastante claro que isso pode acontecer, já que múltiplos caminhos para o mesmo nó podem resultar no mesmo elemento na fila em vários lugares.

    Seu código original é, de fato, a melhor maneira de fazer isso.

    • 7

relate perguntas

  • Lock Condition.notify está lançando java.lang.IllegalMonitorStateException

  • Resposta de microsserviço Muitos para Um não aparece no carteiro

  • Validação personalizada do SpringBoot Bean

  • Os soquetes Java são FIFO?

  • Por que não é possível / desencorajado definir um lado do servidor de tempo limite de solicitação?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve