1.兩數之和
1. 兩數之和
給定一個整數數組?nums
?和一個整數目標值?target
,請你在該數組中找出?和為目標值?target
? 的那?兩個?整數,并返回它們的數組下標。
你可以假設每種輸入只會對應一個答案,并且你不能使用兩次相同的元素。
你可以按任意順序返回答案。
示例 1:
輸入:nums = [2,7,11,15], target = 9 輸出:[0,1] 解釋:因為 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
輸入:nums = [3,2,4], target = 6 輸出:[1,2]
示例 3:
輸入:nums = [3,3], target = 6 輸出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只會存在一個有效答案
進階:你可以想出一個時間復雜度小于?O(n2)
?的算法嗎?
我的
public int[] twoSum(int[] nums, int target) {Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();for(int i=0;i<nums.length;i++){int temp = target - nums[i];if(hashtable!=null && hashtable.containsKey(temp)){return new int[]{hashtable.get(temp),i};}hashtable.put(nums[i],i);}return null;}
別人的
class Solution {public int[] twoSum(int[] nums, int target) {int length = nums.length;for(int i = 0; i < length - 1; i++){int back_i = length - i - 1;for(int j = i + 1; j < length; j++){int back_j = length - j - 1;if(nums[i] + nums[j] == target){return new int[]{i,j};}if(nums[back_i] + nums[back_j] == target){return new int[]{back_i, back_j};}}}return new int[0];}
}
思路不一樣:
思路不一樣 每次不止比較1對數的和
2.字母異位詞分組
49. 字母異位詞分組
給你一個字符串數組,請你將?字母異位詞?組合在一起。可以按任意順序返回結果列表。
字母異位詞?是由重新排列源單詞的所有字母得到的一個新單詞。
示例 1:
輸入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
輸出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
輸入: strs = [""]
輸出: [[""]]
示例 3:
輸入: strs = ["a"]
輸出: [["a"]]
提示:
1 <= strs.length <= 104
0 <= strs[i].length <= 100
strs[i]
?僅包含小寫字母
我的
class Solution {public static List<List<String>> groupAnagrams(String[] strs) {List<List<String>> resData = new ArrayList<>();for(int i = 0 ; i<strs.length ; i++){String sortedString = sortString(strs[i]);if(resData.size() == 0){List<String> innerList = new LinkedList<>();innerList.add(sortedString);innerList.add(strs[i]);resData.add(innerList);}else{Boolean isOld = false;for(int j = 0 ; j<resData.size(); j++){String existingSortedString = resData.get(j).get(0);if(sortedString.equals(existingSortedString)){List<String> innerList = resData.get(j);innerList.add(strs[i]);resData.set(j,innerList);isOld = true;break;}}if (!isOld){//isNewList<String> innerList = new ArrayList<>();innerList.add(sortedString);innerList.add(strs[i]);resData.add(innerList);}}}for(int j = 0 ; j<resData.size(); j++){List<String> innerList = resData.get(j);innerList.remove(0);resData.set(j,innerList);}// 按內部 List 的 size 升序排序Collections.sort(resData, new Comparator<List<?>>() {@Overridepublic int compare(List<?> list1, List<?> list2) {return Integer.compare(list1.size(), list2.size());}});return resData;}public static String sortString(String input) {// 將字符串轉換為字符數組char[] charArray = input.toCharArray();// 對字符數組進行排序Arrays.sort(charArray);// 將排序后的字符數組轉換為字符串return new String(charArray);}}
別人的
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {public List<List<String>> groupAnagrams(String[] strs) {return new AbstractList<List<String>>() {private final List<List<String>> list = new ArrayList<>();public void initList() {if (list.isEmpty()) {Map<String, List<String>> map = new HashMap();for(String s:strs){char[] cc=s.toCharArray();Arrays.sort(cc);String key =Arrays.toString(cc);List<String>list=map.getOrDefault(key, new ArrayList());list.add(s);map.put(key,list);}list.addAll(map.values());}}@Overridepublic List<String> get(int index) {initList();return list.get(index);}@Overridepublic int size() {initList();return list.size();}};}}
?思路一樣,實現方式的優化:
確定每個字符串通過同一排序規則得到唯一排序字符串,由此判斷是否為由相同字母組成的字符串,加入到同一list 去掉每個內層list的第一位 按內層list的size從小到大排序
0.1.代碼總結
public static void main(String[] args) {// 1int[] nums = {2,7,11,15};int target = 9;int[] twoSum = twoSum2(nums, target);System.out.println(Arrays.toString(twoSum));// 2String[] strs = {"eat","tea","tan","ate","nat","bat"};List<List<String>> groupAnagrams = groupAnagrams2(strs);System.out.println(groupAnagrams);}public static int[] twoSum2(int[] nums, int target) {//思路不一樣 每次不止比較1對數的和int length = nums.length;for(int i = 0; i < length - 1; i++){int back_i = length - i - 1;for(int j = i + 1; j < length; j++){int back_j = length - j - 1;if(nums[i] + nums[j] == target){return new int[]{i,j};}if(nums[back_i] + nums[back_j] == target){return new int[]{back_i, back_j};}}}return new int[0];}//2-answerpublic static List<List<String>> groupAnagrams2(String[] strs) {return new AbstractList<List<String>>() {private final List<List<String>> list = new ArrayList<>();public void initList() {if (list.isEmpty()) {Map<String, List<String>> map = new HashMap();for(String s:strs){//1.sort 思路:確定每個字符串通過同一排序規則得到唯一排序字符串char[] cc=s.toCharArray();Arrays.sort(cc);String key = Arrays.toString(cc);//2.addList 由唯一排序字符串判斷是否為由相同字母組成的字符串,加入到同一listList<String> list = map.getOrDefault(key, new ArrayList());list.add(s);map.put(key, list);}list.addAll(map.values());}}@Overridepublic List<String> get(int index) {initList();return list.get(index);}@Overridepublic int size() {initList();return list.size();}};}//1-mypublic static int[] twoSum(int[] nums, int target) {Map<Integer, Integer> map = new HashMap<Integer, Integer>();for(int i=0;i<nums.length;i++){int temp = target - nums[i];//思路if(map!=null && map.containsKey(temp)){return new int[]{map.get(temp),i};}map.put(nums[i],i);}return null;}//2-mypublic static List<List<String>> groupAnagrams(String[] strs) {//思路:確定每個字符串通過同一排序規則得到唯一排序字符串,由此判斷是否為由相同字母組成的字符串加入到同一list//去掉每個內層list的第一位//按內層list的size從小到大排序List<List<String>> resData = new ArrayList<>();for(int i = 0 ; i<strs.length ; i++){String sortedString = sortString(strs[i]);if(resData.size() == 0){List<String> innerList = new LinkedList<>();innerList.add(sortedString);innerList.add(strs[i]);resData.add(innerList);}else{Boolean isOld = false;for(int j = 0 ; j<resData.size(); j++){String existingSortedString = resData.get(j).get(0);if(sortedString.equals(existingSortedString)){List<String> innerList = resData.get(j);innerList.add(strs[i]);resData.set(j,innerList);isOld = true;break;}}if (!isOld){//isNewList<String> innerList = new ArrayList<>();innerList.add(sortedString);innerList.add(strs[i]);resData.add(innerList);}}}for(int j = 0 ; j<resData.size(); j++){List<String> innerList = resData.get(j);innerList.remove(0);resData.set(j,innerList);}// 按內部 List 的 size 升序排序Collections.sort(resData, new Comparator<List<?>>() {@Overridepublic int compare(List<?> list1, List<?> list2) {return Integer.compare(list1.size(), list2.size());}});return resData;}public static String sortString(String input) {// 將字符串轉換為字符數組char[] charArray = input.toCharArray();// 對字符數組進行排序Arrays.sort(charArray);// 將排序后的字符數組轉換為字符串return new String(charArray);}
0.2.相關
AI:使用通俗易懂的例子的來講解AbstractList
看起來用戶可能在學習Java集合框架,特別是想深入理解如何自定義List實現。
用戶可能已經了解了AbstractList的基本用法,但希望有更簡單、生活化的例子來加深理解。他們可能對之前的技術示例感到有些復雜,或者需要更直觀的解釋來鞏固概念。需要將AbstractList的概念與實際生活中的場景結合,幫助用戶形成直觀印象。
需要確定用戶的基礎水平。之前的回答涉及到了代碼示例,所以用戶可能有一定的編程經驗,但可能需要更基礎的比喻或例子。例如,用日常生活中的事物來類比AbstractList的作用,比如菜單、書架等。
用戶的需求不僅僅是知道如何用代碼實現,而是理解AbstractList存在的意義和適用場景。可能需要強調為什么使用AbstractList而不是直接實現List接口,比如減少必須實現的方法數量,提供默認實現等。
另外,用戶可能想知道在什么情況下應該繼承AbstractList,比如需要自定義列表行為,或者包裝現有數據結構。需要提供簡單明了的例子,比如只讀列表、固定大小列表,或者組合多個列表的情況。
需要避免使用過于技術化的術語,轉而使用比喻和簡單代碼示例。例如,用書架的比喻來解釋不可變列表,用購物清單來演示可變列表的實現。同時,對比直接實現List接口和繼承AbstractList的差異,突出AbstractList的便利性。
還要注意用戶可能的誤區,比如認為繼承AbstractList必須實現所有方法,而實際上只需要實現get和size。或者對于修改操作,默認會拋出異常,需要覆蓋set、add等方法才能支持修改。
最后,確保例子涵蓋不同的使用場景,如不可變列表、包裝現有數組、動態擴展的列表等,幫助用戶全面理解AbstractList的靈活性和實用性。
好的!我用一個?「菜單本」?的比喻來幫你理解?AbstractList
,并配上一個超簡單的代碼例子。
📖?比喻場景
假設你要做一個?「飯店菜單系統」,但有個特殊要求:
-
普通服務員只能?查看?菜單(不能修改)
-
店長有?修改菜單?的權限
如果用?AbstractList
?來實現,就像這樣:
🎯?代碼實現
import java.util.AbstractList;
import java.util.Arrays;
import java.util.List;// 自定義菜單類(繼承AbstractList)
class Menu extends AbstractList<String> {private String[] dishes; // 存儲菜品// 構造方法public Menu(String[] dishes) {this.dishes = Arrays.copyOf(dishes, dishes.length);}// 必須實現的方法1:獲取菜品(普通服務員用)@Overridepublic String get(int index) {return dishes[index];}// 必須實現的方法2:獲取菜單長度@Overridepublic int size() {return dishes.length;}// 可選實現:修改菜品(只有店長能調用)@Overridepublic String set(int index, String newDish) {String oldDish = dishes[index];dishes[index] = newDish;return oldDish; // 返回被替換的舊菜名}
}public class Test {public static void main(String[] args) {// 初始菜單String[] initialDishes = {"魚香肉絲", "宮保雞丁", "麻婆豆腐"};List<String> menu = new Menu(initialDishes);// 普通服務員查看菜單System.out.println("當前菜單:" + menu); // 輸出:[魚香肉絲, 宮保雞丁, 麻婆豆腐]// 嘗試修改菜單(會報錯,因為沒權限)// menu.add("水煮魚"); // 拋出 UnsupportedOperationException// 店長修改第二道菜if (menu instanceof Menu) {Menu bossMenu = (Menu) menu;String old = bossMenu.set(1, "辣子雞");System.out.println("替換掉:" + old); // 輸出:替換掉:宮保雞丁}System.out.println("新菜單:" + menu); // 輸出:[魚香肉絲, 辣子雞, 麻婆豆腐]}
}
🔑?關鍵點解析
-
為什么用 AbstractList?
-
它幫你實現了?
List
?接口中大部分復雜方法(如?iterator()
) -
你只需專注實現?
get()
?和?size()
?這兩個核心方法
-
-
修改控制:
-
默認所有修改方法(如?
add()
、remove()
)會拋出異常 -
如果想讓某些角色能修改,只需覆蓋對應方法(比如例子中的?
set()
)
-
-
實際應用場景:
-
創建?只讀列表(不覆蓋修改方法)
-
包裝現有數組(如例子中的?
String[] dishes
) -
實現特殊規則的列表(如固定長度列表、組合多個列表)
-
💡?對比直接實現 List 接口
如果不用?AbstractList
,你需要實現?List
?接口的?24個方法!而用?AbstractList
?只需要實現?2個方法,其他方法已有默認實現。
就像做菜單時,有人幫你寫好了打印菜單、搜索菜品等功能,你只需告訴它「菜品存在哪」和「有多少道菜」。