599. 两个列表的最小索引总和

本文介绍了一种高效的算法,帮助Andy和Doris在最短索引和条件下找到他们共同喜欢的餐厅。通过使用哈希映射和遍历,找出两个列表中具有最小索引之和的相同餐厅。

难度:简单

假设 Andy 和 Doris 想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。

你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设答案总是存在。

示例 1:

输入: list1 = ["Shogun", "Tapioca Express", "Burger King", "KFC"],list2 = ["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。

示例 2:

输入:list1 = ["Shogun", "Tapioca Express", "Burger King", "KFC"],list2 = ["KFC", "Shogun", "Burger King"]
输出: ["Shogun"]
解释: 他们共同喜爱且具有最小索引和的餐厅是“Shogun”,它有最小的索引和1(0+1)。

提示:

  • 1 <= list1.length, list2.length <= 1000
  • 1 <= list1[i].length, list2[i].length <= 30 
  • list1[i] 和 list2[i] 由空格 ' ' 和英文字母组成。
  • list1 的所有字符串都是 唯一 的。
  • list2 中的所有字符串都是 唯一 的。

代码:

class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
        //餐厅名为key,下标索引为value
        Map<String, Integer> map = new HashMap<>(list1.length);
        for (int i = 0; i < list1.length; i++) {
            map.put(list1[i], i);
        }
        //与list2比较
        List<String> list = new ArrayList<>();
        Integer min = Integer.MAX_VALUE;
        for (int i = 0; i < list2.length; i++) {
            if (map.containsKey(list2[i])) {
                //当更小的索引和出现
                if (map.get(list2[i]) + i < min) {
                    list.clear();
                    list.add(list2[i]);
                    min = map.get(list2[i]) + i;
                } else if (map.get(list2[i]) + i == min) {
                    list.add(list2[i]);
                }
            }
        }
        return list.toArray(new String[list.size()]);
    }
}

为了将一个包含 `2N` 个元素的数组划分为两个大小各为 `N` 的子数组,使得这两个子数组的和之差最小,可以采用贪心算法或者动态规划来解决。以下是一个基于贪心思想的实现方法。 ### 思路 1. **排序与贪心选择**:首先对数组进行排序,然后从中间开始,尝试通过调整划分位置来最小化两部分的和的差。 2. **滑动窗口法**:使用双指针技术,从数组两端向中间移动,分别计算左右两部分的和,并调整指针以缩小两者之间的差距。 3. **递归优化**:如果需要更精确的结果,可以结合回溯或 DFS 来探索所有可能的划分方式,从而找到最优解。 ### 示例代码 ```cpp #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; // 计算两个子数组和的最小差值划分 pair<vector<int>, vector<int>> minDifferencePartition(vector<int>& nums) { int n = nums.size() / 2; sort(nums.begin(), nums.end()); // 排序以便于贪心策略应用 vector<int> left, right; int sumLeft = 0, sumRight = 0; // 初始分配,前n个给left,后n个给right for (int i = 0; i < n; ++i) { left.push_back(nums[i]); sumLeft += nums[i]; } for (int i = n; i < 2 * n; ++i) { right.push_back(nums[i]); sumRight += nums[i]; } int minDiff = abs(sumLeft - sumRight); // 尝试交换元素以减少差值 for (int i = 0; i < n; ++i) { for (int j = n; j < 2 * n; ++j) { int newSumLeft = sumLeft - nums[i] + nums[j]; int newSumRight = sumRight + nums[i] - nums[j]; int diff = abs(newSumLeft - newSumRight); if (diff < minDiff) { // 更新最小差值及相关数组 minDiff = diff; swap(left[i], right[j - n]); // 注意索引偏移 sumLeft = newSumLeft; sumRight = newSumRight; } } } return {left, right}; } int main() { vector<int> nums = {3, 1, 4, 2, 5, 6}; // 示例输入 auto result = minDifferencePartition(nums); cout << "Left array: "; for (int num : result.first) { cout << num << " "; } cout << endl; cout << "Right array: "; for (int num : result.second) { cout << num << " "; } cout << endl; return 0; } ``` ### 说明 - **排序**:通过排序可以更好地应用贪心策略,因为较大的数更容易影响总和的变化。 - **初始划分**:将前 `N` 个元素分配到第一个子数组,剩下的分配到第二个子数组。 - **交换优化**:遍历所有可能的交换组合,寻找能使和的差值最小化的交换操作。 - **时间复杂度**:最坏情况下为 O(N²),适用于中等规模的数据集。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值