172、两个列表的最小索引总和

本文介绍了一种算法,用于找出两个人共同喜爱的餐厅,通过最小的索引和来确定最佳选择。算法使用HashMap存储餐厅及其索引,然后比较两个列表,找到共同的餐厅并计算总索引和,最后返回索引和最小的餐厅。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

示例 1:

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

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

两个列表的长度范围都在 [1, 1000]内。
两个列表中的字符串的长度将在[1,30]的范围内。
下标从0开始,到列表的长度减1。
两个列表都没有重复的元素。

实现起来比较复杂,但是思路很清晰,所以一遍就通过了
代码如下:

class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
      
		//考虑使用map来存储所有的东西,并且第一个表示的是字符串,第二个表示的是索引
		Map<String, Integer> map = new HashMap<>();
		int i = 1;
		for (String string : list1) {
			//记录下字符串与其对应的索引
			map.put(string, i++);
		}
		i = 1;
		for (String string : list2) {
			//取出其对应的索引
			if(map.get(string) != null){
				map.put(string, map.get(string) + i );
			}
			i++;
		}
		i = 1;
		for (String string : list1) {
			//去除list1中有的但是list2中没有的字符串
			if(map.get(string) == i){
				map.remove(string);
			}
			i ++;
		}
	//	System.out.println(map.toString());
		if(map.size() == 1){
			String [] result = new String[1];

			for (String string : map.keySet()) {
				result[0] = string;
				return result;
			}
		}else {
			int min = Integer.MAX_VALUE;
			for (String string : map.keySet()) {
				if(min > map.get(string)){
					min = map.get(string);
				}
			}
			List<String> temList = new ArrayList<>();
			for (String string : map.keySet()) {
				if(min == map.get(string)){
					temList.add(string);
				}
			}
			
			String[] arr = (String[])temList.toArray(new String[temList.size()]);
			
			return arr;
		}
		return new String[-1];
  
    }
}

排名靠前的代码,很简单,把我的那个三个for循环改成了两个,不得不说思路很好

class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
        Map<String, Integer> map = new HashMap<>();
        int min = Integer.MAX_VALUE;
        List<String> resList = new ArrayList<>();
        for (int i = 0; i < list1.length; i++) {
            map.put(list1[i], i);
        }
        for (int i = 0; i < list2.length && i <= min; i++) {
            if (map.containsKey(list2[i])) {
                int sum = i + map.get(list2[i]);
                if (sum < min) {
                    resList.clear();
                    resList.add(list2[i]);
                    min = sum;
                } else if (sum == min) {
                    resList.add(list2[i]);
                }
            }
        }
        return resList.toArray(new String[resList.size()]);
    }
}
<think>嗯,我现在得解决这个问题,题目是找出数组中两个索引,它们的元素之等于特定值。然后返回升序排列的这两个索引,如果有多个的话,选小索引最小的那个。比如例子里的数组[1,2,3,-2,5,7],总和是7,返回的是[1,4],也就是2+5=7的情况。那我得仔细怎么实现这个。 首先,我得理解题目要求。输入是数组长度、数组元素、特定值。输出两个索引,按升序排列。如果有多个解的话,要选其中第一个索引最小的那个。比如如果有两个解,比如索引对(0,5)(1,2),那么应该选0较小的那个。但如果有多个解的第一个索引相同的话,可能要看第二个索引更小的?或者题目中的“索引对中小索引最小”具体怎么理解?比如,比如索引对(1,4)(1,3),这候应该选哪个?应该选第二个索引更小的那个吗?题目中的描述是“若有多组符合情况则输出索引对中小索引最小的一组”,这里的“小索引”可能指的是整个索引对中最小的那个?比如比如,比如两个解是(0,5)(1,2),那么01中的最小是0,所以选第一个。如果是(1,3)(2,3),那么最小索引分别是12,所以选前者。那这种情况下,我们的遍历方式应该按顺序找到第一个满足条件的对,然后返回。 那解决问题的思路应该是怎样的呢?直接的方法是双重循环遍历所有可能的两个元素的,找到第一个符合条件的索引对。然后返回升序排列后的结果。因为一旦找到第一个满足条件的,按照题目中的条件,如果有多个解,那么第一个被找到的应该就是小索引最小的。例如,当外层循环i从0开始,内层循环j从i+1开始,这样一旦找到nums[i] + nums[j]等于目标值,就返回ij,因为此i是可能的最小值,并且j也是i之后的最小可能的。这样就能满足题目中的条件。因为如果有多个解,例如当i=0可能有多个j满足,此i是0,是所有可能解中最小的i,所以直接返回第一个遇到的即可。或者,如果i=0的候没有解,i=1的候找到j,这候就是下一个可能的最小解。所以双重循环的顺序应该可以保证正确的结果。 那接下来,如何实现这个逻辑呢? 首先,输入的处理。需要读入数组长度n,然后读入数组元素。接着读入目标值target。然后遍历所有可能的ij的组合,i从0到n-2,j从i+1到n-1。计算两者的是否等于target。一旦找到第一个符合条件的对,就记录ij,然后立即返回。这样就能保证索引对的小索引最小的,因为外层循环i是按从小到大的顺序遍历的,而内层j也是从i+1开始,所以当找到一个,i是尽可能小的,而j也是i之后的最小的可能,所以整个索引对的升序排列是ij,所以直接输出ij的顺序即可。 例如,在例子中,数组是[1,2,3,-2,5,7]。目标值是7。遍历i=0,检查j=1到5。i=0,数组元素是1,那么找是否有元素等于7-1=6。数组中的元素是2、3、-2、5、7。对应的索引是1到5。那么当j=4,元素是5,1+5=6?哦,原例子的总和是7。原例子的输出是索引14,对应的元素是25,总和是7。所以可能我之前的分析有问题,或者例子中的总和是7,所以目标值是7。这候,当i=1,元素是2,那么需要找7-2=5。然后在数组中i=1后面的元素中找有没有5。数组中的元素是3,-2,5,7。对应的索引是2到5。当j=4的候,元素是5,所以i=1,j=4,总和是7,满足条件。所以返回这两个索引,按升序排列是14。所以代码在这种情况下会正确返回。 那双重循环的顺序是否正确?比如当i=0的候,数组元素是1,需要找是否有元素等于7-1=6。数组中的元素是2,3,-2,5,7。后面的元素有没有6?没有。所以i=0的候没有找到。然后i=1的候,找7-2=5,后面是否有5?是的,j=4的候是5。所以这候返回14。所以双重循环的顺序是正确的。 那这样的话,代码的大致结构应该是这样的: 读取n,数组,target。 然后循环i从0到n-1: 循环j从i+1到n-1: 如果array[i] + array[j] == target: 输出ij,并返回。 这样就能保证找到的第一个符合条件的对是i最小的,并且j尽可能小。这样就能满足题目中的条件,即索引对中小的索引最小的那一组。例如,假设存在两个解,比如i=0,j=5i=1,j=2。那么当i=0,j=5会被先找到,所以返回05。而i=1的情况不会被遍历到,直到i=0的所有j都遍历完毕之后。所以这样的双重循环可以保证第一个找到的解是i最小的。 那这样的话,这样的算法是正确的。 那现在需要考虑如何实现这个逻辑。在C语言中,如何读取输入? 输入描述中的第一行是数组的长度,不超过100。第二行是数组元素。第三行是特定值。例如输入样例中的数组长度是6,数组是1 2 3 -2 5 7,特定值是7。输出是1 4。 所以C代码需要读取n,然后读取n个整数到数组,再读取target。然后进行双重循环。一旦找到,就输出ij的顺序,按升序排列,即ij已经满足i<j,所以直接输出ij即可。 那具体的代码结构: #include <stdio.h> int main() { int n; scanf("%d", &n); int nums[100]; // 题目中说长度不超过100 for (int i = 0; i < n; ++i) { scanf("%d", &nums[i]); } int target; scanf("%d", &target); // 双重循环查找 for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { if (nums[i] + nums[j] == target) { printf("%d %d\n", i, j); return 0; // 直接结束程序,找到第一个符合条件的 } } } // 根据题目描述,应该至少存在一个解?或者需要考虑无解的情况? // 题目描述中的例子存在解,但输入是否有解需要看具体情况。但题目可能保证有解? // 题目中的输出描述要求输出一行,假设总有一个解存在,否则可能需要处理。例如,假设题目保证存在解,所以无需处理。 // 但实际情况下可能需要考虑找不到的情况,比如输出什么?但题目可能不会给出这种情况的测试用例。所以这里可能不需要处理。 return 0; } 这样的代码应该能解决问题吗? 比如测试用例的情况。当数组是[1,2,3,-2,5,7],target是7,双重循环的顺序: i=0,j从1到5: 检查1+2=3?不等于7。j=1:1+2=3。j=2:1+3=4。j=3:1+(-2)=-1。j=4:1+5=6。j=5:1+7=8。都不等于7。所以i=0没有找到。 i=1,j从2到5: i=1的元素是2。检查j=2(3)的总和5。不等于7。j=3是-2:2+(-2)=0。j=4是5:2+5=7,符合。所以i=1,j=4。输出1 4。程序结束。 那这样就正确了。 那这样的情况是正确的。 那如果存在多个解,比如比如数组中有多个符合条件的对,那么会返回第一个遇到的,也就是i最小的那个。例如数组[3,4,2,5],target是7。可能的解有i=0,j=1(3+4=7),i=1,j=3(4+3=7?假设数组是[3,4,2,5],那么i=0,j=1是3+4=7;i=2,j=3是2+5=7。那么在代码中,外层循环i=0的候,j=1就找到了,所以会返回01。而不会到i=2的情况。所以符合题目条件。 所以这样的代码是正确的。 那这样,这个代码应该能符合题目要求。那这样应该就是正确的解法。</think>以下是解决该问题的C语言代码,按照题目要求找到两个总和为特定值的索引,并确保输出符合条件的最小索引对: ```c #include <stdio.h> int main() { int n; scanf("%d", &n); int nums[100]; for (int i = 0; i < n; ++i) { scanf("%d", &nums[i]); } int target; scanf("%d", &target); // 双重循环遍历所有可能的索引对 for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { if (nums[i] + nums[j] == target) { printf("%d %d", i, j); return 0; // 找到第一个符合条件的对后立即结束 } } } return 0; } ``` ### 代码说明: 1. **输入处理**: - 读取数组长度 `n`。 - 读取数组元素到 `nums` 中。 - 读取目标值 `target`。 2. **双重循环遍历**: - 外层循环变量 `i` 从 `0` 到 `n-1`,表示一个索引。 - 内层循环变量 `j` 从 `i+1` 到 `n-1`,表示第二个索引。 - 检查 `nums[i] + nums[j]` 是否等于 `target`,若满足则立即输出并结束程序。 3. **输出特性**: - 一旦找到符合条件的索引对,直接输出 `i` `j`(由于 `i < j`,结果自然升序)。 - 双重循环的顺序保证了优先返回**小索引最小**的解(即遍历顺序是从左到右,优先找到更小的 `i`)。 ### 示例验证: 输入: ``` 6 1 2 3 -2 5 7 7 ``` 输出: ``` 1 4 ``` 代码通过双重循环找到 `nums[1] + nums[4] = 2 + 5 = 7`,符合要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值