智能算法 | 刷题的方法真的找到正确思路了嘛

简介: 智能算法 | 刷题的方法真的找到正确思路了嘛

大家在学习编程、算法,刷题的时候,真正的苦恼在于没有一套行之有效的刷题顺序。


引言

从何学起,先学什么,再学什么。力扣(Leetcode)上两千道题目,怎么刷,很多人刷题的效率低,主要体现在如下三点:


  • 找题
  • 找到了不合适现阶段做的题
  • 没有全套的优质题解可以参考
    而市面上基本找不到真正能解决以上痛点的算法书籍。

一些书籍是每个知识点蜻蜓点水,然后就叫大家举一反三。

一些书籍是一堆题解堆在一起,让大家学起来感受不到知识的连贯性和系统性。

断片式的学习,效率怎么能高呢?


在学习算法的时候,就深感其中的艰难,当的题量达到一定数量时候,随着反复的琢磨和深入的思考,我再去回顾这些算法题目,发现如果要是按照合理的顺序来刷题,那效果一定是 事半功倍!


每一个专题中的题目按照由易到难的顺序进行编排,每一道题目所涉及的知识,前面都会有相应的题目做知识铺垫,做到环环相扣。


建议大家按照章节顺序阅读本书,在阅读的过程中会发现在题目编排上的良苦用心!


本书不仅在题目编排上精心设计,而且在针对读者最头痛的算法问题上做了详细且深入的讲解。


关于动态规划,都知道递推公式的重要性,但dp数组的含义、dp数组的初始化、遍历顺序以及如何打印dp数组来排查Bug,这些都很重要。例如,解决背包问题的时候,遍历顺序才是最关键的,也是最难理解的。


关于回溯算法,题目要求集合之间不可重复,那么就需要去重,各种资料都说要去重,但没有说清楚是“树层去重”还是“树枝去重”——这是我为了说明去重的过程而创造的两个词汇。


关于KMP算法,都知道使用前缀表进行回退,可什么是前缀表,为什么一定要用前缀表,根据前缀表回退有几种方式,这些却没有说清楚,导致最后大家看的一头雾水。


关于二叉树,不同的遍历顺序其递归函数究竟如何安排,递归函数什么时候需要返回值,什么时候不用返回值,什么情况下分别使用前、中、后序遍历,迭代法又要如何实现,这些都决定了对二叉树的理解是否到位。


华为2023最新面试题

以下题为最新的leetcode会员付费华为面试题

让我们一起开始吧!

由于篇幅限制,我们将题目使用引用的方式大家可以直接跳转去先尝试一下,并只介绍其开头部分简单题,获取完整题目可以点击文章底部微信进行私聊

对称二叉树

题目地址:点击这里跳转即可

  1. 数据结构:二叉树

二叉树常用于搜索,父节点有两个左右节点,有可能会退化为链表

  1. 动图帮助理解


  1. 规律

左子树的左孩子 == 右子树 的右孩子

左子树的右孩子 == 右子树 的左孩子

  1. 终止条件
    //递归的终止条件是两个节点都为空
    //或者两个节点中有一个为空
    //或者两个节点的值不相等
    if(left==null && right==null) {
      return true;
    }
    if(left==null || right==null) {
      return false;
    }
    if(left.val!=right.val) {
      return false;
    }


两个数组的交集

题目地址:点击这里跳转即可

  1. 数据结构 : 数组
    一组连续的内存空间存储一组具有相同类型的数据的集合,需要额外注意的是扩容操作,刚开始默认容量为10,然后1.5倍进行扩容,最后copyof复制进去


  1. 暴力思路
    双重循环去比较,注意唯一,把重复的去掉统统暴力
  2. 我的错误思路
    我用的ArrayList和HashMap,他一直不能保证唯一
    下面第一个代码是错的
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Map<Integer, Integer> numFreqMap = new HashMap<>();
        List<Integer> intersection = new ArrayList<>();
        // 统计 nums1 中每个数字的出现频率
        for (int num : nums1) {
            numFreqMap.put(num, numFreqMap.getOrDefault(num, 0) + 1);
        }
        // 遍历 nums2,寻找和 nums1 重复的数字
        for (int num : nums2) {
            if (numFreqMap.containsKey(num) && numFreqMap.get(num) > 0) {
                intersection.add(num);
                numFreqMap.put(num, numFreqMap.get(num) - 1);
            }
        }
        // 将结果转换为数组
        int[] result = new int[intersection.size()];
        for (int i = 0; i < intersection.size(); i++) {
            result[i] = intersection.get(i);
        }
        return result;
    }
}


应该用set

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> set2 = new HashSet<>();
        List<Integer> intersection = new ArrayList<>();
        // 将 nums1 中的元素添加到 set1
        for (int num : nums1) {
            set1.add(num);
        }
        // 在 set1 中查找和 nums2 重复的元素
        for (int num : nums2) {
            if (set1.contains(num) && !set2.contains(num)) {
                intersection.add(num);
                set2.add(num);
            }
        }
        // 将结果转换为数组
        int[] result = new int[intersection.size()];
        for (int i = 0; i < intersection.size(); i++) {
            result[i] = intersection.get(i);
        }
        return result;
    }
}


总之就是数据结构犯了错误

使用Set和Map都可以找到两个数组的交集,但是它们有不同的适用情况和功能。


Set是一种集合数据结构,它存储唯一元素并提供高效的成员查询。在找到数组交集的情况下,我们可以利用Set的唯一性来避免重复元素的出现。首先,我们可以将一个数组中的元素添加到一个Set中。然后,遍历第二个数组,判断元素是否在Set中存在,如果存在,则这个元素是交集的一部分。Set的实现在内部使用哈希表,这样可以快速进行元素查找和插入操作,因此执行效率较高。


Map是一种键值对数据结构,它可以通过键快速查找对应的值。在交集问题中,我们可以将数组中的元素作为键,并将出现的次数作为值存储在Map中。遍历第二个数组时,可以在Map中查找对应键,如果存在且值大于0,则将该键添加到交集中,并将值减1。这样可以实现统计交集元素及其重复次数的功能。然而,如果我们只关注元素的唯一性而不考虑重复次数,使用Map相对于Set来说增加了一些额外的复杂性,因为我们需要处理值的递减操作。

数据结构小结

我觉得在研究算法之前首先是要拿下数据结构,可以让我们更好的理解题意,在文章的最后带大家梳理一下数据结构的基础内容



我们以数组作为底层,它包括了优先队列,双端队列(堆栈),还有不完美哈希,那么先说不完美哈希,在解决哈希冲突的时候,我们使用了开放寻址法,分离法,这些底层都是数组加链表结构,然后双端队列,就是线性结构堆栈,最后说一下优先队列,优先队列是线性数据结构中队列的一种实现队列还有一种实现是延迟队列,它的底层是链表,链表也是一种线性数据结构,底层为双向链表。而优先队列又是树形结构,堆。树形数据结构除了堆之外还有数组作为底层的字典树。还有二叉树,而二叉树为了自平衡出现了AVL自平衡二叉树,还有2-3树和对应的红黑树,这几个树的底层都是指针,同样作为数组为底层的还有并查集和邻接矩阵,这个并查集属于树形数据结构,而邻接矩阵是属于图的一类,图还包括了邻接表,他的数据结构为链表和红黑树,除此之外还有一种数据结构叫做布隆过滤器,他的底层实现为位数组和哈希函数。

相关文章
|
1月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
29天前
|
存储
基于遗传算法的智能天线最佳阵列因子计算matlab仿真
本课题探讨基于遗传算法优化智能天线阵列因子,以提升无线通信系统性能,包括信号质量、干扰抑制及定位精度。通过MATLAB2022a实现的核心程序,展示了遗传算法在寻找最优阵列因子上的应用,显著改善了天线接收功率。
|
1月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
38 2
|
1月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
51 9
|
1月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
51 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
1月前
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
14 0
|
3月前
|
JavaScript 算法 前端开发
JS算法必备之String常用操作方法
这篇文章详细介绍了JavaScript中字符串的基本操作,包括创建字符串、访问特定字符、字符串的拼接、位置查找、大小写转换、模式匹配、以及字符串的迭代和格式化等方法。
JS算法必备之String常用操作方法
|
3月前
|
JavaScript 算法 前端开发
JS算法必备之Array常用操作方法
这篇文章详细介绍了JavaScript中数组的创建、检测、转换、排序、操作方法以及迭代方法等,提供了数组操作的全面指南。
JS算法必备之Array常用操作方法
|
2月前
|
机器学习/深度学习 算法 Python
群智能算法:深入解读人工水母算法:原理、实现与应用
近年来,受自然界生物行为启发的优化算法备受关注。人工水母算法(AJSA)模拟水母在海洋中寻找食物的行为,是一种新颖的优化技术。本文详细解读其原理及实现步骤,并提供代码示例,帮助读者理解这一算法。在多模态、非线性优化问题中,AJSA表现出色,具有广泛应用前景。
|
3月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
40 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法