代码随想录算法训练营第6天 | 242.有效的字母异位词、 349. 两个数组的交集、202.快乐数、1.两数之和

242.有效的字母异位词

题目链接:有效的字母异位词

1.解题思路

题目是为了查找两个字符串中字符出现的频率是否相同。

设置一个大小为26的数组,利用阿斯卡码值转换为数组位置实现,当多一个就++

对另外一个,当出现一个,对应位置就--

直到数组全部位置为0就是,否则不是。

2.我的实现
实现遇到的问题

字符转换成数组下标位置:

int n=x-'a';
array[n]++;

字符串的遍历:

for (char x:s.toCharArray()
     ) {//在这里x已经获得了s中的字符
    int n=x-'a';
    array[n]++;

}

解释for-each:

int[] array = {1, 2, 3};

for (int num : array) {
    System.out.println(num);
}
---->

for (int i = 0; i < array.length; i++) {
    int num = array[i];
    System.out.println(num);
}

即会把数组或字符串中的每一个遍历赋值给x


解释toCharArray():

String str = "Hello, World!";
char[] charArray = str.toCharArray();
--->

转换后的 charArray 内容如下:

['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']

即toCharArray() 方法会将字符串中的每个字符复制到一个新的字符数组中,并返回这个数组,

回值是一个数组。

代码
public boolean isAnagram(String s, String t) {
        int[] array=new int[26];

        for (char x:s.toCharArray()
             ) {//在这里x已经获得了s中的字符
            int n=x-'a';
            array[n]++;

        }
        for (char x:t.toCharArray()
             ) {
            int n=x-'a';
            array[n]--;
        }
        for (int i = 0; i < array.length; i++) {
            if (array[i]!=0){
                return false;
            }
        }
        return true;


    }
代码中的错误

3.标准实现
/**
 * 242. 有效的字母异位词 字典解法
 * 时间复杂度O(m+n) 空间复杂度O(1)
 */
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];

        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;     // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
        }

        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        
        for (int count: record) {
            if (count != 0) {               // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        return true;                        // record数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}
区别

区别不大

charAt的解释
public char charAt(int index)
返回值是一个char类型,返回字符串中下标为i的字符。

4.题目总结

当数据较少时,可以用数组类型做哈希表。

349. 两个数组的交集

题目链接:两个数组的交集

1.解题思路

返回两个数组中相同的元素,元素不能重复,没有返回顺序要求。

将num1的所有数值放到哈希表里,再遍历num2,num2中元素是否出现在哈希表里,如果出现就放进result数组中。

2.我的实现
实现遇到的问题

这次遇到的问题比较多,第一次接触哈希表,所以查了很多资料,我放在set的主要功能及用法里面

可以直接打印set:

Set 中元素的某些类型实现了合适的 toString() 方法

将set中的元素加到数组中:

int j=0;
for (int x:
     hashSet2) {
    result[j++]=x;
}
代码
    public int[] intersection(int[] nums1, int[] nums2) {
        //创建set
        Set<Integer>  hashSet=new HashSet<>();//用来接收nums1
        Set<Integer>  hashSet2=new HashSet<>();//用来接收result
        //添加元素
        for (int x:
             nums1) {
            hashSet.add(x);
        }
        //用另一个set接收交集
        for (int i = 0; i < nums2.length; i++) {
            if (hashSet.contains(nums2[i])){
                hashSet2.add(nums2[i]);
            }
        }
        //将set转化为数组
        int[] result=new int[hashSet2.size()];//创建一个大小与接收set大小一样的数组
        int j=0;
        for (int x:
             hashSet2) {
            result[j++]=x;
        }
        return result;
    }
代码中的错误:

没什么大错误

3.标准实现
import java.util.HashSet;
import java.util.Set;

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
      
        //方法1:将结果集合转为数组

        return resSet.stream().mapToInt(x -> x).toArray();
        
        //方法2:另外申请一个数组存放setRes中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        
        return arr;
    }
}
4.题目总结

数组

适合场景:

  • 简单键值对存储:如果你需要存储简单的键值对,并且键是连续的整数(如从 0 开始),数组是一个简单而高效的选择。数组在访问和存储元素时非常高效,时间复杂度为 O(1)

局限性:

  • 数组不能处理非整数或非连续的键,不能动态调整大小(除非使用ArrayList),也不适合存储重复键。

set

适合场景:

  • 存储唯一元素:当你需要存储一组唯一元素(没有重复),并且对元素的顺序没有要求时,Set 是理想选择。Set 自动处理哈希冲突,且能快速插入、删除和查找元素,时间复杂度通常为 O(1)。 

局限性:

  • Set 只适合存储唯一元素,不能存储键值对,因此无法直接查找与某个键关联的值。

map

适合场景:

  • 键值对存储:当你需要存储键值对,并且键不是连续的整数时,Map 是最佳选择。Map 允许你通过键来快速查找对应的值,通常时间复杂度为 O(1)。它非常适合需要根据键查找值的场景。

局限性:

  • Map 允许键重复(如果使用HashMap,会覆盖原有值),可能会有性能开销(特别是涉及到哈希冲突时),且不保证键的顺序(如果使用HashMap)。

总结

  • 使用数组:当键是连续整数且需要快速访问时使用数组。
  • 使用Set:当你需要存储唯一元素且不关心顺序时使用Set
  • 使用Map:当你需要存储键值对,且需要通过键快速查找对应的值时使用Map

202.快乐数

题目链接:快乐数

1.解题思路

题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

这其实就是循环的结束条件。当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。

所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。

2.我的实现
实现遇到的问题

取各个位上的数值:

public static int pfh(int n){
    int sum=0;
    while (n>0){
        int tmp=n%10;
        sum+=tmp*tmp;
        n=n/10;
    }
    return sum;
}

代码
    public boolean isHappy(int n) {

        Set<Integer> set=new HashSet<>();//默认是空的
        while (true){
            if (pfh(n)==1){
                return true;
            }else {
                set.add(n);
                n=pfh(n);
                if (set.contains(n)){
                    return false;
                }
            }
        }


    }
    //创建一个计算每位数平方和的方法
    public static int pfh(int n){
        int sum=0;
        while (n>0){
            int tmp=n%10;
            sum+=tmp*tmp;
            n=n/10;
        }
        return sum;
    }

代码中的错误

3.标准实现
class Solution {
    public boolean isHappy(int n) {
        Set<Integer> record = new HashSet<>();
        while (n != 1 && !record.contains(n)) {
            record.add(n);
            n = getNextNumber(n);
        }
        return n == 1;
    }

    private int getNextNumber(int n) {
        int res = 0;
        while (n > 0) {
            int temp = n % 10;
            res += temp * temp;
            n = n / 10;
        }
        return res;
    }
}

区别

        while (n != 1 && !record.contains(n)) {
            record.add(n);
            n = getNextNumber(n);
        }
        return n == 1;

这里条件写得更简洁,当n==1或record中包含了n时就停止循环

4.题目总结
  • 循环检测:使用 Set 来检测是否进入了循环。若发现一个平方和结果已经出现过,说明数 n 会进入无限循环,不是快乐数。

1.两数之和

题目链接:两数之和

1.解题思路

当要判断这个元素是否出现在集合中时,要想到用哈希法

需要判断一个元素是否遍历过,我们每次把遍历过的元素n加到集合里,我们需要判断需要的元素(result-n)是否在集合里出现过。

使用map,以出现过的元素作为key,这个元素对应的下标作为value

2.我的实现
实现遇到的问题

在后续Map的主要功能和用法中

代码
 public int[] twoSum(int[] nums, int target) {

        int[] result = new int[2];
        if(nums == null || nums.length == 0){
            return result;
        }

        //创建一个map储存nums中的元素和其下标
        Map<Integer,Integer> map=new HashMap<>();

        //因为不能重复用里面的元素,所以应该先判断了再收集
        map.put(nums[0],0);
        for (int i = 1; i < nums.length; i++) {
            int tmp=target-nums[i];
            if (map.containsKey(tmp)){
                result[0]=map.get(tmp);//先找前面的再添加,防止两个相等
                map.put(nums[i],i);//相等的key对应的value会被更新
                result[1]=map.get(nums[i]);
                return result;
            }
            map.put(nums[i],i);
        }
        return result;
    }

代码中的错误

需要注意的在上述代码注释中

3.标准实现
//使用哈希表
public int[] twoSum(int[] nums, int target) {
    int[] res = new int[2];
    if(nums == null || nums.length == 0){
        return res;
    }
    Map<Integer, Integer> map = new HashMap<>();
    for(int i = 0; i < nums.length; i++){
        int temp = target - nums[i];   // 遍历当前元素,并在map中寻找是否有匹配的key
        if(map.containsKey(temp)){
            res[1] = i;
            res[0] = map.get(temp);
            break;
        }
        map.put(nums[i], i);    // 如果没找到匹配对,就把访问过的元素和下标加入到map中
    }
    return res;
}

区别

其实在map是空的时候也检测不到temp,因为是先检测再增添,所以可以从i=0时开始遍历。

4.题目总结

这个题目主要考察了算法的优化思路,利用哈希表可以将原本 O(n^2) 的时间复杂度降低到 O(n)。同时,注意题目中的唯一解、不能重复使用元素以及返回下标等要求是解决这个问题的关键。

Set 的主要功能及用法

1. 创建 Set

Set 是一个接口,因此你不能直接实例化它。通常使用其实现类来创建 Set 对象。

Set<String> hashSet = new HashSet<>();
Set<String> linkedHashSet = new LinkedHashSet<>();
Set<String> treeSet = new TreeSet<>();

  • HashSet:不保证元素顺序,基于哈希表实现,最常用。
  • LinkedHashSet:保证元素的插入顺序,基于哈希表和链表实现。
  • TreeSet:保证元素的自然顺序(或者使用 Comparator 进行排序),基于红黑树实现。
2. 添加元素

使用 add() 方法将元素添加到 Set 中。Set 不允许重复元素,如果尝试添加一个已经存在的元素,add() 方法会返回 false

Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");

boolean isAdded = set.add("Apple"); // 返回 false,因为 "Apple" 已经存在

3. 删除元素

使用 remove() 方法删除 Set 中的指定元素。

set.remove("Banana"); // 删除 "Banana"

4. 检查元素是否存在

使用 contains() 方法检查 Set 中是否存在某个元素。

boolean hasApple = set.contains("Apple"); // 返回 true
boolean hasGrape = set.contains("Grape"); // 返回 false

5. 获取 Set 的大小

使用 size() 方法获取 Set 中元素的数量。

int size = set.size(); // 返回 2,因为有 "Apple" 和 "Orange"

6. 遍历 Set

你可以使用 for-each 循环或迭代器来遍历 Set 中的元素。

// 使用 for-each 循环
for (String fruit : set) {
    System.out.println(fruit);
}

// 使用迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

7. 清空 Set

使用 clear() 方法可以清空 Set 中的所有元素。

set.clear(); // 清空 Set

8. 判断 Set 是否为空

使用 isEmpty() 方法检查 Set 是否为空。

boolean isEmpty = set.isEmpty(); // 如果 Set 为空则返回 true

Map 的主要功能和用法 


Map 是 Java 中的一种集合类型,用于存储键值对(key-value pairs)。在 Map 中,每个键(key)都是唯一的,并且每个键都映射到一个值(value)。Map 提供了一系列操作,方便开发者进行数据存储、查找、更新和删除操作。下面是 Map 的主要功能及其用法    

1. 创建 Map

Map 是一个接口,不能直接实例化。常用的实现类有 HashMapLinkedHashMapTreeMap

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        // HashMap 实例化
        Map<String, Integer> hashMap = new HashMap<>();

        // LinkedHashMap 实例化
        Map<String, Integer> linkedHashMap = new LinkedHashMap<>();

        // TreeMap 实例化
        Map<String, Integer> treeMap = new TreeMap<>();
    }
}

  • HashMap:不保证顺序,基于哈希表实现,查找和插入的速度最快。
  • LinkedHashMap:按插入顺序排列键值对,基于哈希表和双向链表实现。
  • TreeMap:按键的自然顺序或自定义顺序排列,基于红黑树实现。

     

2. 添加和更新键值对

使用 put() 方法添加或更新键值对。如果键已经存在,put() 方法会更新其对应的值

Map<String, Integer> map = new HashMap<>();
map.put("Apple", 10);  // 添加键值对
map.put("Banana", 20);
map.put("Apple", 15);  // 更新键 "Apple" 的值

3. 查找值

使用 get() 方法根据键查找对应的值。如果键不存在,返回 null

 int value = map.get("Apple"); // 返回 15
Integer nonExistentValue = map.get("Orange"); // 返回 null

4. 检查键或值是否存在
  • containsKey(Object key):检查是否存在指定的键。
  • containsValue(Object value):检查是否存在指定的值。

 boolean hasApple = map.containsKey("Apple"); // 返回 true
boolean hasValue10 = map.containsValue(10);  // 返回 false

5. 删除键值对

使用 remove() 方法根据键删除对应的键值对。如果键存在,返回其对应的值;否则,返回 null

int removedValue = map.remove("Banana"); // 返回 20 并移除键 "Banana"
Integer nonExistentRemove = map.remove("Orange"); // 返回 null

6. 获取 Map 的大小

使用 size() 方法获取 Map 中键值对的数量。

int size = map.size(); // 返回 1,因为有 1 对键值对

7. 遍历 Map

可以通过 keySet()values()entrySet() 方法来遍历 Map

// 遍历键
for (String key : map.keySet()) {
    System.out.println("Key: " + key);
}

// 遍历值
for (Integer value : map.values()) {
    System.out.println("Value: " + value);
}

// 遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

8. 清空 Map

使用 clear() 方法可以清空 Map 中的所有键值对。

map.clear(); // 清空 Map

9. 判断 Map 是否为空

使用 isEmpty() 方法检查 Map 是否为空。

 boolean isEmpty = map.isEmpty(); // 如果 Map 为空,则返回 true

Map 的常见实现类及应用场景
  • HashMap:适用于大多数情况下的键值对存储,尤其是当顺序不重要时。它提供最快的查找和插入性能。

  • LinkedHashMap:适用于需要维护插入顺序或访问顺序的场景,常用于实现缓存(如 LRU 缓存)。

  • TreeMap:适用于需要按键的自然顺序或自定义顺序排列键值对的场景,如按字母顺序排序的单词计数器。

总结

Map 是 Java 中非常强大的集合类型,用于高效存储和查找键值对。选择合适的 Map 实现类(HashMapLinkedHashMapTreeMap)可以根据具体需求优化性能和功能。

      

  • 26
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值