列表

详情


2101. 引爆最多的炸弹

给你一个炸弹列表。一个炸弹的 爆炸范围 定义为以炸弹为圆心的一个圆。

炸弹用一个下标从 0 开始的二维整数数组 bombs 表示,其中 bombs[i] = [xi, yi, ri] 。xi 和 yi 表示第 i 个炸弹的 X 和 Y 坐标,ri 表示爆炸范围的 半径 。

你需要选择引爆 一个 炸弹。当这个炸弹被引爆时,所有 在它爆炸范围内的炸弹都会被引爆,这些炸弹会进一步将它们爆炸范围内的其他炸弹引爆。

给你数组 bombs ,请你返回在引爆 一个 炸弹的前提下,最多 能引爆的炸弹数目。

 

示例 1:

输入:bombs = [[2,1,3],[6,1,4]]
输出:2
解释:
上图展示了 2 个炸弹的位置和爆炸范围。
如果我们引爆左边的炸弹,右边的炸弹不会被影响。
但如果我们引爆右边的炸弹,两个炸弹都会爆炸。
所以最多能引爆的炸弹数目是 max(1, 2) = 2 。

示例 2:

输入:bombs = [[1,1,5],[10,10,5]]
输出:1
解释:
引爆任意一个炸弹都不会引爆另一个炸弹。所以最多能引爆的炸弹数目为 1 。

示例 3:

输入:bombs = [[1,2,3],[2,3,1],[3,4,2],[4,5,3],[5,6,4]]
输出:5
解释:
最佳引爆炸弹为炸弹 0 ,因为:
- 炸弹 0 引爆炸弹 1 和 2 。红色圆表示炸弹 0 的爆炸范围。
- 炸弹 2 引爆炸弹 3 。蓝色圆表示炸弹 2 的爆炸范围。
- 炸弹 3 引爆炸弹 4 。绿色圆表示炸弹 3 的爆炸范围。
所以总共有 5 个炸弹被引爆。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int maximumDetonation(vector<vector<int>>& bombs) { } };

javascript 解法, 执行用时: 98 ms, 内存消耗: 56.1 MB, 提交时间: 2024-07-22 09:08:55

/**
 * @param {number[][]} bombs
 * @return {number}
 */
var maximumDetonation = function(bombs) {
    const n = bombs.length;
    // 判断炸弹 u 能否引爆炸弹 v
    const isConnected = (u, v) => {
        const dx = bombs[u][0] - bombs[v][0];
        const dy = bombs[u][1] - bombs[v][1];
        return bombs[u][2] * bombs[u][2] >= dx * dx + dy * dy;
    };
    
    // 维护引爆关系有向图
    const edges = new Map();
    for (let i = 0; i < n; ++i) {
        for (let j = 0; j < n; ++j) {
            if (i !== j && isConnected(i, j)) {
                if (!edges.has(i)) edges.set(i, []);
                edges.get(i).push(j);
            }
        }
    }
    let res = 0; // 最多引爆数量
    for (let i = 0; i < n; ++i) {
        // 遍历每个炸弹,广度优先搜索计算该炸弹可引爆的数量,并维护最大值
        const visited = Array(n).fill(0);
        let cnt = 1;
        const q = [i];
        visited[i] = 1;
        while (q.length > 0) {
            const cidx = q.shift();
            for (const nidx of edges.get(cidx) || []) {
                if (visited[nidx]) continue;
                ++cnt;
                q.push(nidx);
                visited[nidx] = 1;
            }
        }
        res = Math.max(res, cnt);
    }
    return res;
};

rust 解法, 执行用时: 19 ms, 内存消耗: 2.3 MB, 提交时间: 2024-07-22 09:08:32

use std::collections::{HashMap, VecDeque};
use std::cmp::max;

impl Solution {
    pub fn maximum_detonation(bombs: Vec<Vec<i32>>) -> i32 {
        let n = bombs.len();
    // 判断炸弹 u 能否引爆炸弹 v
        let is_connected = |u: usize, v: usize| -> bool {
            let dx = (bombs[u][0] - bombs[v][0]) as i64;
            let dy = (bombs[u][1] - bombs[v][1]) as i64;
            (bombs[u][2] as i64) * (bombs[u][2] as i64) >= (dx * dx + dy * dy)
        };

        // 维护引爆关系有向图
        let mut edges: HashMap<usize, Vec<usize>> = HashMap::new();
        for i in 0..n {
            for j in 0..n {
                if i != j && is_connected(i, j) {
                    edges.entry(i).or_insert(Vec::new()).push(j);
                }
            }
        }

        let mut res = 0; // 最多引爆数量
        for i in 0..n {
            // 遍历每个炸弹,广度优先搜索计算该炸弹可引爆的数量,并维护最大值
            let mut visited = vec![0; n];
            let mut cnt = 1;
            let mut q = VecDeque::new();
            q.push_back(i);
            visited[i] = 1;
            while let Some(cidx) = q.pop_front() {
                for &nidx in edges.get(&cidx).unwrap_or(&vec![]) {
                    if visited[nidx] == 1 {
                        continue;
                    }
                    cnt += 1;
                    q.push_back(nidx);
                    visited[nidx] = 1;
                }
            }
            res = max(res, cnt);
        }
        res
    }
}

java 解法, 执行用时: 89 ms, 内存消耗: 42.4 MB, 提交时间: 2023-10-10 23:23:48

class Solution {
    int[][] bombs;
    int n;
    boolean[] bombed;  // bombed[i]标记有没有爆炸过该***
    static long[][] dis; // 两个***之间的距离平方

    public int maximumDetonation(int[][] _bombs) {
        /*
        记忆化DFS
        数据范围:1 <= bombs.length <= 100 看题目可以知道***数目比较小,因此可以考虑比较暴力的方法
        1.预处理出么任意两个***之间的距离平方,后面可能会用到
        2.引爆规则:爆炸半径范围内所有***都会爆炸,换句话说就是:半径平方 >= 距离平方
        3.枚举引爆每个***最终能引爆得***数,这个过程用dfs进行模拟,用数组进行记录哪些***被引爆了,最后取最大值
        坑点:注意int溢出
         */
        bombs = _bombs;
        n = bombs.length;
        // 预处理距离平方
        dis = new long[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int x1 = bombs[i][0], y1 = bombs[i][1], x2 = bombs[j][0], y2 = bombs[j][1];
                dis[i][j] = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2);
            }
        }
        int res = 1;
        // 枚举从每个***开始爆炸
        for (int i = 0; i < n; i++) {
            // 一开始所有***都没有爆炸
            bombed = new boolean[n];
            bombed[i] = true;  // 从bombs[i]开始炸
            dfs(i); // 引爆其他的
            // 统计
            int cnt = 0;
            for (int j = 0; j < n; j++) {
                if (bombed[j]) cnt++;
            }
            if (cnt > res) res = cnt;   // 记录最大值
        }
        return res;
    }

    // 从***i开始引爆
    private void dfs(int i) {
        long r = bombs[i][2];  // 当前***i的爆炸半径
        // 枚举所有其他***
        for (int j = 0; j < n; j++) {
            if (bombed[j]) continue;    // ***j炸过了就不重复炸了
            // ***j还没引爆且位于i的爆炸范围,引爆
            if (dis[i][j] <= r * r) {
                bombed[j] = true;   // 引爆***j
                dfs(j); // 从***j出发引爆其他***
            }
        }
    }
}

java 解法, 执行用时: 127 ms, 内存消耗: 41.6 MB, 提交时间: 2023-10-10 23:23:24

class Solution {
    // 炸弹引爆最大数量
    int max = 1;
    // 炸弹是否引爆备忘录
    boolean[] mem;
    public int maximumDetonation(int[][] bombs) {
        mem = new boolean[bombs.length];
        for(int i = 0 ; i < bombs.length ; i ++){
            // 先引爆一个
            dfs(bombs, i);
            // 所有炸弹置为未引爆状态
            Arrays.fill(mem,false);
        }
        return max;
    }

    private int dfs(int[][] bombs, int i){
        if(mem[i]){
            return 0;
        }
        mem[i] = true;
        int ret = 1;
        // 遍历所有炸弹,判断是否会连带引爆
        for(int j = 0 ; j < bombs.length ; j ++){
            if(mem[j]) continue;
            if(canBom(bombs,i,j)){
                // j爆炸之后,会带动其他的炸弹爆炸,继续dfs
                ret += dfs(bombs, j);
            }
        }
        max = Math.max(max,ret);
        return ret;
    }
    
    private boolean canBom(int[][] bombs, int i, int j){
        int[] b1 = bombs[i];
        int[] b2 = bombs[j];
        long x0 = b1[0], x1 = b2[0], y0 = b1[1], y1 = b2[1], r0 = b1[2];
        long len = (y1-y0)*(y1-y0) + (x1-x0)*(x1-x0);
        long r02 = r0 * r0;
        // 【两点距离的平方】(y1-y0)^2 + (x1-x0)^2 < 【引爆半径的平方】r0^2 则会被引爆
        if(len <= r02) return true;
        
        return false;
        
    }
    
}

python3 解法, 执行用时: 736 ms, 内存消耗: 16.2 MB, 提交时间: 2023-10-10 23:21:46

class Solution:
    def maximumDetonation(self, bombs: List[List[int]]) -> int:
        n = len(bombs)
        # 判断炸弹 u 能否引爆炸弹 v
        def isConnected(u: int, v: int) -> bool:
            dx = bombs[u][0] - bombs[v][0]
            dy = bombs[u][1] - bombs[v][1]
            return bombs[u][2] ** 2 >= dx ** 2 + dy ** 2
        
        # 维护引爆关系有向图
        edges = defaultdict(list)
        for i in range(n):
            for j in range(n):
                if i != j and isConnected(i, j):
                    edges[i].append(j)
        res = 0   # 最多引爆数量
        for i in range(n):
            # 遍历每个炸弹,广度优先搜索计算该炸弹可引爆的数量,并维护最大值
            visited = [False] * n
            cnt = 1
            q = deque([i])
            visited[i] = True
            while q:
                cidx = q.popleft()
                for nidx in edges[cidx]:
                    if visited[nidx]:
                        continue
                    cnt += 1
                    q.append(nidx)
                    visited[nidx] = True
            res = max(res, cnt)
        return res

cpp 解法, 执行用时: 112 ms, 内存消耗: 25 MB, 提交时间: 2023-10-10 23:21:26

class Solution {
public:
    int maximumDetonation(vector<vector<int>>& bombs) {
        int n = bombs.size();
        // 判断炸弹 u 能否引爆炸弹 v
        auto isConnected = [&](int u, int v) -> bool {
            long long dx = bombs[u][0] - bombs[v][0];
            long long dy = bombs[u][1] - bombs[v][1];
            return (long long)bombs[u][2] * bombs[u][2] >= dx * dx + dy * dy;
        };
        
        // 维护引爆关系有向图
        unordered_map<int, vector<int>> edges;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i != j && isConnected(i, j)) {
                    edges[i].push_back(j);
                }
            }
        }
        int res = 0;   // 最多引爆数量
        for (int i = 0; i < n; ++i) {
            // 遍历每个炸弹,广度优先搜索计算该炸弹可引爆的数量,并维护最大值
            vector<int> visited(n);
            int cnt = 1;
            queue<int> q;
            q.push(i);
            visited[i] = 1;
            while (!q.empty()) {
                int cidx = q.front();
                q.pop();
                for (const int nidx: edges[cidx]) {
                    if (visited[nidx]) {
                        continue;
                    }
                    ++cnt;
                    q.push(nidx);
                    visited[nidx] = 1;
                }
            }
            res = max(res, cnt);
        }
        return res;
    }
};

golang 解法, 执行用时: 24 ms, 内存消耗: 6.5 MB, 提交时间: 2023-10-10 23:20:57

func maximumDetonation(bombs [][]int) (ans int) {
	n := len(bombs)
	g := make([][]int, n)
	for i, p := range bombs {
		for j, q := range bombs {
			if j != i && (q[0]-p[0])*(q[0]-p[0])+(q[1]-p[1])*(q[1]-p[1]) <= p[2]*p[2] {
				g[i] = append(g[i], j) // 有向图,从 i 向 j 连边,表示引爆 i 可以引爆 j
			}
		}
	}
	for i := range g { // 暴力枚举所有起点,跑 DFS 看能访问到多少节点
		vis := make([]bool, n)
		cnt := 0
		var dfs func(int)
		dfs = func(v int) {
			vis[v] = true
			cnt++
			for _, w := range g[v] {
				if !vis[w] {
					dfs(w)
				}
			}
		}
		dfs(i)
		if cnt > ans {
			ans = cnt
		}
	}
	return
}

上一题