分析
Given an array of integers nums and an integer target, return
indices of the two numbers
such that they add up to target.
You may assume that each input would have exactly one solution, and you maynot use the same element twice
.
You can return the answer in any order.
尋找兩個不同元素相加等於目標值並返回其索引
。
夢開始的地方也是夢夭折的地方!
這個題目,刻意摘錄下原題英文描述,因為我覺得英文描述的更加準確。indices of the two numbers
即返回的是目標資料的索引下標,not use the same element twice
表明,一個索引只能被用一次,即便是比如目標值為10,而索引1對應的元素值為5,還是不能自己跟自己相加,得出錯誤結果[1,1]
。
依據題目的意思,原始的陣列,索引跟資料是一對一繫結,倘若我們自行在這個陣列之上進行去重或者排序都會破壞這個陣列的原有結構,與我們的最終結果背道而馳。在這種情況下,我就需要先將資料元素值和索引下標進行包裝,形成一個獨立的資料。因為資料本身無法獨立存在,需要能夠裝它的容器,很容易想到鍵值對的結構Map
。
接著問題就來了,鍵值對的鍵在此刻是選擇原始的索引下標呢,還是資料元素值呢?倘若我使用的是索引下標,那麼這樣的Map結構就退化到了陣列結構,也就是自己的這種包裝毫無意義。用資料元素值作為索引,類似於一種依賴倒置
,嗯,我需要的也是透過元素尋找索引。
可還沒有解決問題,又該如何去尋找這兩個數呢?嗯,不妨換個思路,target = wrappedA + wrappedB 轉換為 wrappedB = target - wrappedA,有什麼區別嗎?在已知target和遍歷過程中的獲得的確定值wrappedA,去尋找未知的wrappedB,把原本兩個自由量降低為1個自由量,尋找唯一元素,邊存資料,邊找資料
,Hash結構的主場了。
從LeetCode242 Valid-Anagram這道題的解法,可以獲得一些啟示,Hash結構這個容器,一個陣列把資料存放進去,另一個陣列相當於取出與條件相匹配
的資料,在Valid-Anagram中是尋找字母個數相同的所有資料,在這道題取出與放入的資料之和為目標值的資料。
假設桶1[2,2,2],桶2[1,1],桶3[9],桶4[8,8,8,8,8],桶5[5,5,5,5,5,5]目標和是10,我可以得到的組合是(2,8),(1,9),還有(5,5)這三種數值二元組關係。每個桶內都有多個重複的數值元素,這樣就變成了一個組合問題,可以求解處所有的索引對,但是題目只要求返回一個索引對結果。
主類
package com.github.dolphinmind.hash;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author dolphinmind
* @ClassName TwoSum
* @description
* @date 2024/8/9
*/
public class TwoSum {
/**
* 獲取單個結果即返回
* @param nums
* @param target
* @return
*/
public int[] twoSumGetOneResult(int[] nums, int target) {
if (nums == null || nums.length < 2 ) {
return null;
}
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int difference = target - nums[i];
if (map.containsKey(difference)) {
return new int[]{map.get(difference),i};
}
map.put(nums[i],i);
}
return new int[0];
}
/**
* 獲取所有結果
*/
public List<List<Integer>> twoSumGetAllResult(int[] nums, int target) {
if (nums == null | nums.length < 2) {
return null;
}
//值:索引列表
Map<Integer, List<Integer>> map = new HashMap();
// 索引對結果集合
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
for (int index : map.get(complement)) {
List<Integer> pair = new ArrayList<>();
pair.add(index);
pair.add(i);
res.add(pair);
}
}
map.computeIfAbsent(nums[i], k -> new ArrayList<>()).add(i);
}
return res;
}
}
測試類
package com.github.dolphinmind.hashcode;
import com.github.dolphinmind.hash.TwoSum;
import org.junit.Test;
import java.util.List;
/**
* @author dolphinmind
* @ClassName TwoSumTest
* @description
* @date 2024/8/9
*/
public class TwoSumTest {
@Test
public void test_towSumGetOneResult() {
int[] nums = {1,3,5,7,8,9};
int target = 10;
TwoSum twoSum = new TwoSum();
int[] res = twoSum.twoSumGetOneResult(nums, target);
System.out.println("獲取單個索引對結果:"+res[0] + " " + res[1]);
List<Integer> integers = twoSum.twoSumGetAllResult(nums, target).get(0);
System.out.println("獲取所有索引對結果:"+integers.get(0) + " " + integers.get(1));
}
@Test
public void test_towSumGetAllResult() {
int[] nums = {1,1,1,3,5,7,8,9,7,8,9};
int target = 10;
TwoSum twoSum = new TwoSum();
List<List<Integer>> lists = twoSum.twoSumGetAllResult(nums, target);
for (List<Integer> list : lists) {
System.out.println(list.get(0) + " " + list.get(1));
}
System.out.println(lists.get(0));
}
}