You are given a list of countries, each with a unique name, and a list of pairs indicating which countries are at war with each other. Your task is to determine which countries are "safe to invest in." A country is considered safe if it is not at war with any other country.
countries
: An array of strings, each string is a unique country name.wars
: An array of pairs/lists, where each pair [a, b]
means country a
is at war with country b
(and vice versa).Your output should be a list of all country names that are not involved in any war, in any order.
Constraints:
The first step is to understand that a country is unsafe if it appears in any war pair. A brute-force approach would be to check, for each country, whether it appears in any pair in the wars
list. However, this means for every country, we scan the entire wars
list, which can be slow if both lists are large.
To optimize, we can precompute a set of all countries involved in wars. Then, for each country, we just check if it is in this set (which is a fast operation). This shift from repeated scanning to set-based lookup is the key optimization.
Let's break down the steps to solve this efficiently:
[a, b]
in wars
, add both a
and b
to a set called unsafe
.countries
list.unsafe
set, add it to the result list.
We use a set for unsafe
because checking membership in a set is O(1), making our solution efficient even for large input sizes.
Input:
countries = ["USA", "Canada", "Mexico", "Brazil"]
wars = [["USA", "Canada"], ["Mexico", "Brazil"]]
Step 1: Build Unsafe Set
After processing each war pair:
Step 2: Find Safe Countries
We check each country:
Output: []
Another Example:
countries = ["USA", "Canada", "Mexico", "Brazil"]
wars = [["USA", "Canada"]]
["Mexico", "Brazil"]
def safeCountries(countries, wars):
unsafe = set()
for a, b in wars:
unsafe.add(a)
unsafe.add(b)
return [country for country in countries if country not in unsafe]
#include <vector>
#include <string>
#include <unordered_set>
using namespace std;
vector<string> safeCountries(vector<string>& countries, vector<vector<string>>& wars) {
unordered_set<string> unsafe;
for (const auto& pair : wars) {
unsafe.insert(pair[0]);
unsafe.insert(pair[1]);
}
vector<string> res;
for (const string& country : countries) {
if (unsafe.find(country) == unsafe.end()) {
res.push_back(country);
}
}
return res;
}
import java.util.*;
public class Solution {
public List<String> safeCountries(List<String> countries, List<List<String>> wars) {
Set<String> unsafe = new HashSet<>();
for (List<String> pair : wars) {
unsafe.add(pair.get(0));
unsafe.add(pair.get(1));
}
List<String> res = new ArrayList<>();
for (String country : countries) {
if (!unsafe.contains(country)) {
res.add(country);
}
}
return res;
}
}
function safeCountries(countries, wars) {
const unsafe = new Set();
for (const [a, b] of wars) {
unsafe.add(a);
unsafe.add(b);
}
return countries.filter(country => !unsafe.has(country));
}
Brute-force Approach:
For each country, scan all wars to see if it is involved. If there are n
countries and m
wars, this is O(n * m) time.
Optimized Approach (Using Set):
unsafe
set takes O(m) time (since each war adds two entries).unsafe
is O(1) per country, so O(n) total.The main insight is to precompute all unsafe countries using a set, allowing us to quickly determine which countries are safe. This approach is efficient and simple, relying on fast set lookups. By avoiding repeated scans, we reduce the time complexity from O(n * m) to O(n + m), making the solution scalable and elegant.