两个数组的交集、有效的完全平方数、字符串中的第一个唯一字符

博主分享了从Java基础到成为架构师的学习路线,包括每日刷LeetCode算法题,如求交集、判断完全平方数等。通过对比自身解法与优化后的高效解法,强调了算法和数据结构的重要性。同时,博主还提供了相关资源和学习社区,鼓励读者一起学习进步。

🍅 Java学习路线:搬砖工逆袭Java架构师

🍅 简介:Java领域优质创作者🏆、优快云哪吒公众号作者✌ 、Java架构师奋斗者💪

🍅 百日刷题计划:第 14 / 100 天。

🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 

🍅 欢迎点赞 👍 收藏 ⭐留言 📝 

位于半山腰的城堡酒店坐拥港口美景


算法是进阶架构师的基础,基础不牢,地动山摇,2021-8-14起开始刷题,目标100天,300道LeetCode算法题,分享是学习的最好方式,加油,嗨起来。


1、LeetCode 350.两个数组的交集


题目

给定两个数组,编写一个函数来计算它们的交集。

小编菜解

public static int[] intersect(int[] nums1, int[] nums2) {
    List<Integer> list1 = new ArrayList<>();
    List<Integer> list2 = new ArrayList<>();
    for (int i = 0; i < nums1.length; i++) {
        list1.add(nums1[i]);
    }

    for (int i = 0; i < nums2.length; i++) {
        list2.add(nums2[i]);
    }
    return getIntersection(list1,list2);
}

public static int[] getIntersection(List<Integer> list1, List<Integer> list2) {
    if (list1.size()>list2.size()){
        return getIntersection(list2,list1);
    }
    List<Integer> list = new ArrayList<>();
    for (Integer x : list1){
        if (list2.contains(x)){
            list.add(x);
            list2.remove(x);
        }
    }
    int[] ret = new int[list.size()];
    for (int i = 0; i < list.size(); i++) {
        ret[i] = list.get(i);
    }
    return ret;
}

思路及算法

为了降低空间复杂度,首先遍历较短的数组并在哈希表中记录每个数字以及对应出现的次数,然后遍历较长的数组得到交集。

大佬指点江山

public static int[] intersect(int[] nums1, int[] nums2) {
    if (nums1.length>nums2.length){
        return intersect(nums2,nums1);
    }
    Map<Integer,Integer> map = new HashMap<>();
    for (int num : nums1) {
        int count = map.getOrDefault(num,0) + 1;
        map.put(num,count);
    }
    int[] arr = new int[nums1.length];
    int index = 0;
    for (int num : nums2) {
        int count = map.getOrDefault(num,0);
        if (count > 0){
            arr[index++] = num;
            count--;
            if (count > 0){
                map.put(num,count);
            }else {
                map.remove(num);
            }
        }
    }
    return Arrays.copyOfRange(arr,0,index);
}

list的效率肯定是低于map的,而我的list还要进行增删操作,故而效率低于大佬的解答。 

2、LeetCode 387.有效的完全平方数

题目

给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

进阶:不要 使用任何内置的库函数,如  sqrt 。

小编菜解

public static boolean isPerfectSquare(int num) {
    if (num == 1){
        return true;
    }
    for (int i = 2; i < num; i++) {
        if (num%i == 0 && num/i == i){
            return true;
        }
    }
    return false;
}

提示超出时间限制! 

小编菜解进阶版

public static boolean isPerfectSquare(int num) {
    if (num == 1){
        return true;
    }
    int middle = num/2;
    int left = 2;
    int right = num;
    if (num == middle*middle) {
        return true;
    }else if (num > middle*middle){
        left = middle+1;
    }else{
        right = middle - 1;
    }
    for (int i = left; i <= right; i++) {
        if (num%i == 0 && num/i == i){
            return true;
        }
    }
    return false;
}

仍然超出时间限制! 

大佬指点江山

public static boolean isPerfectSquare(int num) {
    if (num == 1){
        return true;
    }
    long left = 2;
    long right = num/2;
    long middle = 0;
    while (left<=right){
        middle = left+(right - left)/2;
        if (num == middle * middle){
            return true;
        }
        if (num > middle * middle){
            left = middle+1;
        }else {
            right = middle - 1;
        }
    }
    return false;
}

真的是菜,什么是二分查找,每次都要进行二分查找,而不是只进行一次,进行一次和不进行,效率上没有任何区别!

3、LeetCode 387.字符串中的第一个唯一字符

题目

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

小编菜解

public static int firstUniqChar(String s) {
    Map<Character,Integer> map = new LinkedHashMap<>();
    //将字符和个数放入map中
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (map.containsKey(c)){
            map.put(c,map.get(c)+1);
        }else{
            map.put(c,1);
        }
    }
    //找到第一个值为1的key,因为是LinkedHashMap,所以顺序和字符串顺序一致
    char find = 0;
    for(Map.Entry<Character,Integer> entry : map.entrySet()){
        if (entry.getValue() == 1){
            find = entry.getKey();
            break;
        }
    }
    //再通过找到的第一个唯一字符,找到它的位置
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == find){
            return i;
        }
    }
    return -1;
}

虽然,写出来了,但肯定不是最优解,麻烦的令人发指。 

大佬指点江山

public static int firstUniqChar(String s) {
    Map<Character,Integer> map = new LinkedHashMap<>();
    //将字符和个数放入map中
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        map.put(c,map.getOrDefault(c,0)+1);
    }
    //再通过找到的第一个唯一字符,找到它的位置
    for (int i = 0; i < s.length(); i++) {
        if (map.get(s.charAt(i))==1){
            return i;
        }
    }
    return -1;
}

大体思路是一样的,只不过我多了一步,不应该啊。

推荐阅读

【100天算法入门 - 每日三题 - Day13】反转字符串、反转字符串中的元音字母、两个数组的交集

【100天算法入门 - 每日三题 - Day12】Nim游戏、3的幂、4的幂

【100天算法入门 - 每日三题 - Day11】丢失的数字、移动零、单词规律

【100天算法入门 - 每日三题 - Day10】二叉树的所有路径、各位相加、丑数 

【100天算法入门 - 每日三题 - Day9】汇总区间、2的幂、有效的字母异位词

【100天算法入门 - 每日三题 - Day8】同构字符串、存在重复元素、翻转二叉树

【100天算法入门 - 每日三题 - Day7】验证回文串、只出现一次的数字、多数元素

...

【100天算法入门 - 每日三题 - Day3】回文数、罗马数字转数字、最大公共前缀

【100天算法入门 - 每日三题 - Day2】二分查找、第一个错误的版本、搜索插入位置

【100天算法入门 - 每日三题 - Day1】二叉树的中序遍历、两数之和、整数反转

<think>好的,我现在要解决的问题是:在Java中如何比较两个字符串数组,找出仅存在于其中一个数组中的字符串。用户提到了交集、并集和差集,可能他们需要的是差集部分。根据提供的引用,我需要先理解现有的代码,然后调整它们来满足需求。 首先,用户提供的引用中,引用[1]和引用[3]提到了交集、并集和差集的方法。其中交集是通过遍历两个数组,检查元素是否存在,而并集则是利用Set的元素唯一性。差集可能是指一个数组有而另一个没有的元素。例如,数组A相对于数组B的差集就是A中存在但B中不存在的元素。 用户的问题是要找到仅存在于其中一个数组中的字符串,也就是两个数组的对称差集。对称差集是两集合中不属于交集的元素,即(A∪B)减去(A∩B)。不过,也有可能用户只需要其中一个方向的差集,比如仅存在第一个数组或仅存在第二个数组的元素。需要进一步明确。 但根据用户的问题描述,“找到仅存在于一个数组中的字符串”,可能是指两个差集的并集,即对称差集。例如,数组A和数组B,找出所有在A中不在B中的元素,加上在B中不在A中的元素。 接下来,我需要参考现有的代码来调整。例如,引用[3]中的intersect方法用于找交集,那么差集可能需要类似的方法。例如,对于数组arr1,差集就是arr1中不在arr2中的元素,反之亦然。 步骤可能包括: 1. 将两个数组转换为集合,以便快速查找。例如,使用HashSet来存储其中一个数组的元素,这样检查是否存在的时间复杂度是O(1)。 2. 遍历第一个数组,将不在第二个集合中的元素收集起来,作为arr1独有的元素。 3. 同样,遍历第二个数组,收集不在第一个集合中的元素,作为arr2独有的元素。 4. 如果用户需要的是两个差集的合集,那么将这两个结果合并即可。否则,如果只需要其中一个方向的差集,就返回相应的部分。 例如,用户的问题可能需要返回两个数组各自的独有元素,或者合并后的结果。需要根据具体情况处理。 另外,需要考虑数组中的重复元素如何处理。例如,如果数组中有重复的字符串,是否要保留重复项。例如,如果arr1中有两个"apple",而arr2中没有,那么差集是否包含两个"apple"。根据常规的集合操作,集合中的元素是唯一的,但如果是数组的话,可能有重复。用户的问题提到的是字符串数组,所以可能需要保留重复元素。不过,这需要明确需求。 在现有的引用代码中,例如交集的方法,是用List来存储结果,然后转换为数组。这样如果原数组有重复元素,结果中可能保留重复的交集元素。例如,如果arr1有两个"apple",而arr2有一个"apple",那么交集可能返回一个"apple"。但差集的情况可能需要保留arr1中的两个"apple"中的另一个。因此,是否需要保留重复元素,可能需要进一步确认。 假设用户需要的是保留所有在第一个数组中出现但不在第二个数组中的元素,包括重复项,那么代码需要遍历数组,逐个检查是否存在于另一个集合中,并收集所有符合条件的元素。例如,对于arr1中的每个元素,如果不在arr2的集合中,就加入差集列表。这样,如果有重复元素,也会被保留。例如,arr1是["a", "a", "b"],arr2是["b"],则差集应该是["a", "a"]。 但另一种情况,如果用户希望差集中的元素唯一,即每个元素只出现一次,那么应该使用Set来处理。这需要明确用户需求。 根据问题描述,用户可能想比较两个字符串数组,找到仅存在于一个数组中的字符串,这里可能指的是每个字符串是否存在于另一个数组中,而不管出现次数。例如,只要某个字符串在另一个数组中出现过,则排除。因此,重复的字符串只要在另一个数组中出现过,就会被排除,否则保留。例如,如果arr1有["a", "a"],arr2没有"a",则差集包括两个"a"。但如果arr2有一个"a",那么arr1的差集就不包含任何"a"。 现在需要编写代码实现这一逻辑。可以参考引用中的方法,例如: public static String[] getUniqueElements(String[] arr1, String[] arr2) { Set<String> set2 = new HashSet<>(Arrays.asList(arr2)); List<String> diff1 = new ArrayList<>(); for (String s : arr1) { if (!set2.contains(s)) { diff1.add(s); } } Set<String> set1 = new HashSet<>(Arrays.asList(arr1)); List<String> diff2 = new ArrayList<>(); for (String s : arr2) { if (!set1.contains(s)) { diff2.add(s); } } // 合并两个差集 diff1.addAll(diff2); return diff1.toArray(new String[0]); } 不过,这样得到的合并结果可能包含重复元素,如果原数组中有重复且在另一个数组中不存在的情况。例如,arr1有["a","a"],arr2没有,则diff1会收集两个"a",而diff2可能没有元素,合并后是两个"a"。但这样是否正确,需要看用户的需求。如果用户希望每个元素只出现一次,那么应该使用Set来存储结果,或者在最后合并时去重。 但根据问题描述,“仅存在于一个数组中的字符串”,这里的“存在”可能指的是元素是否存在,而不是出现的次数。所以,如果某个字符串在arr1中出现多次但不在arr2中,是否要保留多次?可能用户需要的是保留所有出现次数,或者只要存在一次就足够。这需要明确。 假设用户需要的是找出所有在任一数组中存在的元素,但仅在其中一个数组中存在的元素。例如,元素在arr1中出现过至少一次,而在arr2中从未出现,或者反之。此时,对于arr1中的每个元素,如果不在arr2中,则加入结果列表,不管出现次数。同样处理arr2中的元素。此时,结果可能包含重复元素。例如,arr1中的两个"a"都不在arr2中,则结果中出现两次"a"。 如果需要去除重复项,可以在收集的时候使用Set,或者在最后处理。例如,将diff1和diff2转为Set,然后再合并。 例如: public static String[] getUniqueElementsNoDuplicates(String[] arr1, String[] arr2) { Set<String> set2 = new HashSet<>(Arrays.asList(arr2)); Set<String> diff1 = new HashSet<>(); for (String s : arr1) { if (!set2.contains(s)) { diff1.add(s); } } Set<String> set1 = new HashSet<>(Arrays.asList(arr1)); Set<String> diff2 = new HashSet<>(); for (String s : arr2) { if (!set1.contains(s)) { diff2.add(s); } } diff1.addAll(diff2); return diff1.toArray(new String[0]); } 这样得到的数组中的每个元素都是唯一的,即使原数组中有重复。 因此,用户的问题可能需要明确是否需要保留重复元素。但根据常规的集合操作,可能用户需要的是唯一的元素。例如,用户的问题中的例子引用中的交集方法,返回的是交集元素,但代码中可能处理了重复的情况。例如,在引用[3]的代码中: public static String[] intersect(String[] arr1, String[] arr2) { List<String> list = new ArrayList<>(); Set<String> set = new HashSet<>(Arrays.asList(arr1)); for (String s : arr2) { if (set.contains(s)) { list.add(s); } } return list.toArray(new String[0]); } 这里,如果arr2有重复的元素,并且该元素存在于arr1中,那么结果中会包含重复。例如,arr1=["a"], arr2=["a","a"],则返回["a","a"]。这可能符合用户的需求,即保留重复出现的次数。 但如果是差集的情况,假设用户需要保留原数组中的重复元素,只要它们不存在于另一个数组中。例如,arr1=["a","a"], arr2=[],则差集应该包含两个"a"。 所以,在实现差集的时候,是否保留重复取决于用户需求。在用户的问题中,用户可能希望得到所有仅存在于一个数组中的元素,包括重复的情况,因此需要遍历原数组,逐个检查,并将符合条件的元素添加到结果列表中。 综合上述,我需要编写一个方法,找出在两个数组中仅存在于其中一个的所有元素,包括重复项。具体步骤如下: 1. 将第一个数组转换为集合,用于快速判断元素是否存在。 2. 遍历第二个数组,收集所有不在第一个数组中的元素,存入列表diff2。 3. 将第二个数组转换为集合,遍历第一个数组,收集所有不在第二个数组中的元素,存入列表diff1。 4. 合并diff1和diff2,得到所有仅存在于其中一个数组中的元素。 或者,也可以先处理第一个数组的差集,再处理第二个数组的差集,合并两个结果。 例如,实现代码可能如下: public class StringArrayUtil { public static String[] getUniqueElements(String[] arr1, String[] arr2) { Set<String> set2 = new HashSet<>(Arrays.asList(arr2)); List<String> uniqueInArr1 = new ArrayList<>(); for (String s : arr1) { if (!set2.contains(s)) { uniqueInArr1.add(s); } } Set<String> set1 = new HashSet<>(Arrays.asList(arr1)); List<String> uniqueInArr2 = new ArrayList<>(); for (String s : arr2) { if (!set1.contains(s)) { uniqueInArr2.add(s); } } List<String> result = new ArrayList<>(); result.addAll(uniqueInArr1); result.addAll(uniqueInArr2); return result.toArray(new String[0]); } } 这段代码将返回所有在arr1中但不在arr2中的元素,加上所有在arr2中但不在arr1中的元素,保留原数组中的顺序和重复项。例如: arr1 = ["a", "a", "b", "c"] arr2 = ["b", "d", "d"] 结果应该是 ["a", "a", "c", "d", "d"] 如果用户需要的是仅存在于一个数组中的元素,而不重复,可以将结果转为Set后再转回数组。或者根据需求调整代码。 此外,需要注意数组中的null值处理,但假设输入的数组中不包含null。 现在,根据引用中的示例,用户可能希望得到这样的方法。例如,引用[3]中的交集方法,可能返回重复元素,如果原数组中有的话。因此,在差集的实现中也应该保留重复项,除非特别处理。 最后,生成相关问题,例如关于如何处理重复元素、如何优化性能(如使用集合提高查找速度),或者如何获取单方向的差集等。</think>### 如何比较两个字符串数组并找到仅存在于一个数组中的字符串 在Java中,可以通过以下步骤实现比较两个字符串数组,并找出仅存在于其中一个数组中的字符串: 1. **将数组转换为集合**:利用`HashSet`快速判断元素是否存在,时间复杂度为$O(1)$。 2. **遍历数组筛选差集**:分别遍历两个数组,收集仅存在于当前数组且不在另一个集合中的元素。 3. **合并结果**:将两个差集合并,得到最终的唯一元素列表。 #### 示例代码 ```java import java.util.*; public class StringArrayUtil { public static String[] getUniqueElements(String[] arr1, String[] arr2) { // 将arr2转为集合,用于快速判断元素是否存在 Set<String> set2 = new HashSet<>(Arrays.asList(arr2)); List<String> uniqueInArr1 = new ArrayList<>(); for (String s : arr1) { if (!set2.contains(s)) { uniqueInArr1.add(s); // 收集arr1中独有的元素 } } // 将arr1转为集合,用于快速判断元素是否存在 Set<String> set1 = new HashSet<>(Arrays.asList(arr1)); List<String> uniqueInArr2 = new ArrayList<>(); for (String s : arr2) { if (!set1.contains(s)) { uniqueInArr2.add(s); // 收集arr2中独有的元素 } } // 合并两个列表 List<String> result = new ArrayList<>(); result.addAll(uniqueInArr1); result.addAll(uniqueInArr2); return result.toArray(new String[0]); } } ``` #### 代码说明 - **集合转换**:`HashSet`用于快速判断元素是否存在,提升性能[^1]。 - **差集收集**:遍历数组时,若元素不在对方的集合中,则加入结果列表。 - **保留重复项**:若原数组中存在重复且符合条件的元素,结果中会保留这些重复项。例如: - 输入:`arr1 = ["a", "a", "b"]`,`arr2 = ["b", "c"]` - 输出:`["a", "a", "c"]` #### 扩展场景 - **去重需求**:若希望结果中元素唯一,可将结果列表替换为`Set`。 - **单方向差集**:若只需获取`arr1`中独有的元素,只需返回`uniqueInArr1`部分。
评论 126
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值