##### Welcome to Subscribe On Youtube
• import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;

/*

Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a list of favorite restaurants represented by strings.

You need to help them find out their common interest with the least list index sum. If there is a choice tie between answers, output all of them with no order requirement. You could assume there always exists an answer.

Example 1:
Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]

Output: ["Shogun"]

Explanation: The only restaurant they both like is "Shogun".

Example 2:
Input:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]

Output: ["Shogun"]

Explanation: The restaurant they both like and have the least index sum is "Shogun" with index sum 1 (0+1).

Note:
The length of both lists will be in the range of [1, 1000].
The length of strings in both lists will be in the range of [1, 30].
The index is starting from 0 to the list length minus 1.
No duplicates in both lists.

*/

public class Minimum_Index_Sum_of_Two_Lists {

public static void main(String[] args) {
Minimum_Index_Sum_of_Two_Lists out = new Minimum_Index_Sum_of_Two_Lists();
Solution s = out.new Solution();

String[] s1 = new String[]{"Shogun","Tapioca Express","Burger King","KFC"};
String[] s2 = new String[]{"KFC","Burger King","Tapioca Express","Shogun"};
System.out.println(Arrays.toString(s.findRestaurant(s1, s2)));

Solution2 sl2 = out.new Solution2();

String[] s21 = new String[]{"Shogun","Tapioca Express","Burger King","KFC"};
String[] s22 = new String[]{"KFC","Burger King","Tapioca Express","Shogun"};
System.out.println(Arrays.toString(sl2.findRestaurant(s21, s22)));
}

// o(n^2)
public class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
if (list1 == null || list2 == null || list1.length == 0 || list2.length == 0) {
return new String[]{""};
}

// maintain 2 indexes, both pointing to the same restaurant
int index1 = -1; // minus: not-found
int index2 = -1;
int min = Integer.MAX_VALUE;
ArrayList<String> restaurant = new ArrayList<String>(30); // length of strings 1-30

for (int i = 0; i < list1.length; i++) {
for (int j = 0; j < list2.length; j++) {
if (list1[i].equals(list2[j]) && (i + j < min)) {
// record indexes
min = i + j;
restaurant = new ArrayList<String>(30);
} else if (list1[i].equals(list2[j]) && (i + j == min)) {
// choice tie, then print all of them
}
}
}

return restaurant.toArray(new String[restaurant.size()]);

// @note: below has runtime error: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
//return (String[]) restaurant.toArray();
}
}

// o(m+n), extra space
public class Solution2 {
public String[] findRestaurant(String[] list1, String[] list2) {
if (list1 == null || list2 == null || list1.length == 0 || list2.length == 0) {
return new String[]{""};
}

// maintain 2 indexes, both pointing to the same restaurant
int index1 = -1; // minus: not-found
int index2 = -1;
int min = Integer.MAX_VALUE;
ArrayList<String> restaurant = new ArrayList<String>(30); // length of strings 1-30

// @note: use 2 hashmap: 1.store name => index, 2.store sumIndex => word

// store list1 for o(1) access
HashMap<String, Integer> hmList1 = new HashMap<>();
for (int i = 0; i < list1.length; i++) {
hmList1.put(list1[i], i);
}

// store sumIndex => word
int minIndex = Integer.MAX_VALUE;
for (int j = 0; j < list2.length; j++) {
if (hmList1.containsKey(list2[j])) {
// common interest
int sum = j + hmList1.get(list2[j]);
if (sum < minIndex) {
minIndex = sum; // update minIndex

restaurant = new ArrayList<String>(30);
} else if (sum == minIndex) {
}
}
}

return restaurant.toArray(new String[restaurant.size()]);
}
}
}

############

class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
Map<String, Integer> mp = new HashMap<>();
for (int i = 0; i < list2.length; ++i) {
mp.put(list2[i], i);
}
List<String> ans = new ArrayList<>();
int mi = 2000;
for (int i = 0; i < list1.length; ++i) {
if (mp.containsKey(list1[i])) {
int t = i + mp.get(list1[i]);
if (t < mi) {
ans = new ArrayList<>();
mi = t;
} else if (t == mi) {
}
}
}
return ans.toArray(new String[0]);
}
}

• // OJ: https://leetcode.com/problems/minimum-index-sum-of-two-lists/
// Time: O(L1 + L2)
// Space: O(L1)
class Solution {
public:
vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) {
unordered_map<string, int> m;
for (int i = 0; i < list1.size(); ++i) m[list1[i]] = i;
int minSum = INT_MAX;
vector<string> ans;
for (int i = 0; i < list2.size() && i <= minSum; ++i) {
if (m.find(list2[i]) == m.end() || i + m[list2[i]] > minSum) continue;
if (i + m[list2[i]] < minSum) {
ans.clear();
minSum = i + m[list2[i]];
}
ans.push_back(list2[i]);
}
return ans;
}
};

• class Solution:
def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]:
ans = []
mp = {v: i for i, v in enumerate(list2)}
mi = 2000
for i, v in enumerate(list1):
if v in mp:
t = i + mp[v]
if t < mi:
mi = t
ans = [v]
elif t == mi:
ans.append(v)
return ans

############

class Solution(object):
def findRestaurant(self, list1, list2):
"""
:type list1: List[str]
:type list2: List[str]
:rtype: List[str]
"""
minSum = float("inf")
ans = []
d = {}
for i, name in enumerate(list2):
d[name] = i
for i, name in enumerate(list1):
idxSum = i + d.get(name, float("inf"))
if idxSum == minSum:
ans.append(name)
if idxSum < minSum:
ans = [name]
minSum = idxSum
return ans


• func findRestaurant(list1 []string, list2 []string) []string {
mp := make(map[string]int)
for i, v := range list2 {
mp[v] = i
}
mi := 2000
var ans []string
for i, v := range list1 {
if _, ok := mp[v]; ok {
t := i + mp[v]
if t < mi {
ans = []string{v}
mi = t
} else if t == mi {
ans = append(ans, v)
}
}
}
return ans
}

• function findRestaurant(list1: string[], list2: string[]): string[] {
let minI = Infinity;
const res = [];
const map = new Map<string, number>(list1.map((s, i) => [s, i]));
list2.forEach((s, i) => {
if (map.has(s)) {
const sumI = i + map.get(s);
if (sumI <= minI) {
if (sumI < minI) {
minI = sumI;
res.length = 0;
}
res.push(s);
}
}
});
return res;
}


• use std::collections::HashMap;
use std::iter::FromIterator;

impl Solution {
pub fn find_restaurant(list1: Vec<String>, list2: Vec<String>) -> Vec<String> {
let map: HashMap<String, usize> = HashMap::from_iter(list1.into_iter().zip(0..));
let mut res = vec![];
let mut min_i = usize::MAX;
list2.into_iter().enumerate().for_each(|(i, key)| {
if map.contains_key(&key) {
let sum_i = map.get(&key).unwrap() + i;
if sum_i <= min_i {
if (sum_i < min_i) {
min_i = sum_i;
res.clear();
}
res.push(key);
}
}
});
res
}
}


• class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
int length1 = list1.length, length2 = list2.length;
int leastIndexSum = Integer.MAX_VALUE;
Map<String, Integer> list1Map = new HashMap<String, Integer>();
Map<Integer, List<String>> indexSumInterestMap = new HashMap<Integer, List<String>>();
for (int i = 0; i < length1; i++)
list1Map.put(list1[i], i);
for (int i = 0; i < length2; i++) {
String interest = list2[i];
if (!list1Map.containsKey(interest))
continue;
int indexSum = list1Map.get(interest) + i;
List<String> interests = indexSumInterestMap.getOrDefault(indexSum, new ArrayList<String>());
indexSumInterestMap.put(indexSum, interests);
if (indexSum < leastIndexSum)
leastIndexSum = indexSum;
}
List<String> interestsList = indexSumInterestMap.getOrDefault(leastIndexSum, new ArrayList<String>());
int length = interestsList.size();
String[] interests = new String[length];
for (int i = 0; i < length; i++)
interests[i] = interestsList.get(i);
return interests;
}
}

############

class Solution {
public String[] findRestaurant(String[] list1, String[] list2) {
Map<String, Integer> mp = new HashMap<>();
for (int i = 0; i < list2.length; ++i) {
mp.put(list2[i], i);
}
List<String> ans = new ArrayList<>();
int mi = 2000;
for (int i = 0; i < list1.length; ++i) {
if (mp.containsKey(list1[i])) {
int t = i + mp.get(list1[i]);
if (t < mi) {
ans = new ArrayList<>();
mi = t;
} else if (t == mi) {
}
}
}
return ans.toArray(new String[0]);
}
}

• // OJ: https://leetcode.com/problems/minimum-index-sum-of-two-lists/
// Time: O(L1 + L2)
// Space: O(L1)
class Solution {
public:
vector<string> findRestaurant(vector<string>& list1, vector<string>& list2) {
unordered_map<string, int> m;
for (int i = 0; i < list1.size(); ++i) m[list1[i]] = i;
int minSum = INT_MAX;
vector<string> ans;
for (int i = 0; i < list2.size() && i <= minSum; ++i) {
if (m.find(list2[i]) == m.end() || i + m[list2[i]] > minSum) continue;
if (i + m[list2[i]] < minSum) {
ans.clear();
minSum = i + m[list2[i]];
}
ans.push_back(list2[i]);
}
return ans;
}
};

• class Solution:
def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]:
ans = []
mp = {v: i for i, v in enumerate(list2)}
mi = 2000
for i, v in enumerate(list1):
if v in mp:
t = i + mp[v]
if t < mi:
mi = t
ans = [v]
elif t == mi:
ans.append(v)
return ans

############

class Solution(object):
def findRestaurant(self, list1, list2):
"""
:type list1: List[str]
:type list2: List[str]
:rtype: List[str]
"""
minSum = float("inf")
ans = []
d = {}
for i, name in enumerate(list2):
d[name] = i
for i, name in enumerate(list1):
idxSum = i + d.get(name, float("inf"))
if idxSum == minSum:
ans.append(name)
if idxSum < minSum:
ans = [name]
minSum = idxSum
return ans


• func findRestaurant(list1 []string, list2 []string) []string {
mp := make(map[string]int)
for i, v := range list2 {
mp[v] = i
}
mi := 2000
var ans []string
for i, v := range list1 {
if _, ok := mp[v]; ok {
t := i + mp[v]
if t < mi {
ans = []string{v}
mi = t
} else if t == mi {
ans = append(ans, v)
}
}
}
return ans
}

• function findRestaurant(list1: string[], list2: string[]): string[] {
let minI = Infinity;
const res = [];
const map = new Map<string, number>(list1.map((s, i) => [s, i]));
list2.forEach((s, i) => {
if (map.has(s)) {
const sumI = i + map.get(s);
if (sumI <= minI) {
if (sumI < minI) {
minI = sumI;
res.length = 0;
}
res.push(s);
}
}
});
return res;
}


• use std::collections::HashMap;
use std::iter::FromIterator;

impl Solution {
pub fn find_restaurant(list1: Vec<String>, list2: Vec<String>) -> Vec<String> {
let map: HashMap<String, usize> = HashMap::from_iter(list1.into_iter().zip(0..));
let mut res = vec![];
let mut min_i = usize::MAX;
list2.into_iter().enumerate().for_each(|(i, key)| {
if map.contains_key(&key) {
let sum_i = map.get(&key).unwrap() + i;
if sum_i <= min_i {
if (sum_i < min_i) {
min_i = sum_i;
res.clear();
}
res.push(key);
}
}
});
res
}
}