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个方法,其他方法已有默认实现。
就像做菜单时,有人帮你写好了打印菜单、搜索菜品等功能,你只需告诉它「菜品存在哪」和「有多少道菜」。