LeetCode -- Flora -- edit 2025-04-16

发布于:2025-04-17 ⋅ 阅读:(83) ⋅ 点赞:(0)

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){//isNew
                    List<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<?>>() {
            @Override
            public 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());
                }
            }

            @Override
            public List<String> get(int index) {
                initList();
                return list.get(index);
            }

            @Override
            public int size() {
                initList();
                return list.size();
            }
        };
    }

}

 思路一样,实现方式的优化:

确定每个字符串通过同一排序规则得到唯一排序字符串,由此判断是否为由相同字母组成的字符串,加入到同一list
去掉每个内层list的第一位
按内层list的size从小到大排序

0.1.代码总结

    public static void main(String[] args) {

        // 1
        int[] nums = {2,7,11,15};
        int target = 9;
        int[] twoSum = twoSum2(nums, target);
        System.out.println(Arrays.toString(twoSum));

        // 2
        String[] 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-answer
    public 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 由唯一排序字符串判断是否为由相同字母组成的字符串,加入到同一list
                        List<String> list = map.getOrDefault(key, new ArrayList());
                        list.add(s);
                        map.put(key, list);
                    }
                    list.addAll(map.values());
                }
            }

            @Override
            public List<String> get(int index) {
                initList();
                return list.get(index);
            }

            @Override
            public int size() {
                initList();
                return list.size();
            }
        };
    }

    //1-my
    public 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-my
    public 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){//isNew
                    List<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<?>>() {
            @Override
            public 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:获取菜品(普通服务员用)
    @Override
    public String get(int index) {
        return dishes[index];
    }

    // 必须实现的方法2:获取菜单长度
    @Override
    public int size() {
        return dishes.length;
    }

    // 可选实现:修改菜品(只有店长能调用)
    @Override
    public 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);  
        // 输出:[鱼香肉丝, 辣子鸡, 麻婆豆腐]
    }
}

🔑 关键点解析

  1. 为什么用 AbstractList?

    • 它帮你实现了 List 接口中大部分复杂方法(如 iterator()

    • 你只需专注实现 get() 和 size() 这两个核心方法

  2. 修改控制

    • 默认所有修改方法(如 add()remove())会抛出异常

    • 如果想让某些角色能修改,只需覆盖对应方法(比如例子中的 set()

  3. 实际应用场景

    • 创建 只读列表(不覆盖修改方法)

    • 包装现有数组(如例子中的 String[] dishes

    • 实现特殊规则的列表(如固定长度列表、组合多个列表)


💡 对比直接实现 List 接口

如果不用 AbstractList,你需要实现 List 接口的 24个方法!而用 AbstractList 只需要实现 2个方法,其他方法已有默认实现。

就像做菜单时,有人帮你写好了打印菜单、搜索菜品等功能,你只需告诉它「菜品存在哪」和「有多少道菜」。


网站公告

今日签到

点亮在社区的每一天
去签到