算法小白的进阶之路(力扣1~5)

news2025/1/16 5:10:47

  💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。



非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
 

前言

本栏目将记录博主暑假从0开始刷力扣的算法题,每一条题目我都会把知识点抽丝剥茧地进行分析,以便大家更好的理解和学习,话不多说,肝!

序号标题力扣序号
1杨辉三角I118
2杨辉三角II119
3移动零283
4区域和检索 -数组不可变303
5第三大的数414


1.杨辉三角I

题目:

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

解题思路:

杨辉三角的性质: 每个位置上的数等于它上方两个数之和。

代码(go)

func generate(numRows int) [][]int {
    ans := make([][]int, numRows)
    for i := range ans {
        ans[i] = make([]int, i+1)
        ans[i][0] = 1
        ans[i][i] = 1
        for j := 1; j < i; j++ {
            ans[i][j] = ans[i-1][j] + ans[i-1][j-1]
        }
    }
    return ans
}

下面是代码的具体解析

  1. 行初始化: ans[i] = make([]int, i+1) 创建一个长度为 i+1 的数组,用于存储第 i 行的元素。

  2. 边界处理:

    • ans[i][0] = 1:第一个元素始终为1,因为每行的开头和结尾都是1。
    • ans[i][i] = 1:最后一个元素也为1,因为杨辉三角每一行的首尾都是1。
  3. 中间元素计算:

    • 对于每一行的中间元素,即 1 到 i-1 之间的元素,通过上一行对应位置的元素相加得到。具体计算公式为 ans[i][j] = ans[i-1][j-1] + ans[i-1][j]。这里利用了杨辉三角的性质:每个位置上的数等于它上方两个数之和。
  4. 返回结果: 返回完成填充的二维数组 ans,其中包含了从第0行到第 numRows-1 行的所有元素。

j1 开始,因为杨辉三角每一行的首尾元素都是 1,不需要重新计算。


2.杨辉三角II

题目:

给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

方式一:递推

解题思路:

杨辉三角的性质: 每个位置上的数等于它上方两个数之和。 

此题和上面那道杨辉三角解法类似,区别就是此题rowIndex是索引,所以需要+1

代码(go):

func getRow(rowIndex int) []int {
    C := make([][]int, rowIndex+1)
    for i := range C {
        C[i] = make([]int, i+1)
        C[i][0], C[i][i] = 1, 1
        for j := 1; j < i; j++ {
            C[i][j] = C[i-1][j-1] + C[i-1][j]
        }
    }
    return C[rowIndex]
}

方式二:

利用滚动数组进行优化

解题思路:

注意到对第 i+1 行的计算仅用到了第 i 行的数据,因此可以使用滚动数组的思想优化空间复杂度。

优化后的代码只需要计算两行的杨辉三角即可,可以节省内存空间

代码(go)

func getRow(rowIndex int) []int {
    var pre, cur []int
    for i := 0; i <= rowIndex; i++ {
        cur = make([]int, i+1)
        cur[0], cur[i] = 1, 1
        for j := 1; j < i; j++ {
            cur[j] = pre[j-1] + pre[j]
        }
        pre = cur
    }
    return pre
}

代码解析:

  • pre:前一行的数组。
  • cur:当前行的数组,随着每一行的生成而更新。
  • cur[j] = pre[j-1] + pre[j]:根据杨辉三角的性质,当前行的第 j 列的值等于上一行的第 j-1 列和第 j 列的和。
  • pre = cur:将当前行 cur 赋给 pre,作为下一行的基础。

方式三:

只用一个数组,进一步优化

解题思路:

我们使用一维数组,然后从右向左遍历每个位置。

每个位置的元素res[j] += 其左边的元素 res[j−1]。  row[j] += row[j-1]

第0行只有1

第1行刚刚开始是1,根据公式得出 11 

第2行刚刚开始是11,,根据公式111 ---> 121

第3行刚刚开始是121,根据公式121--->1211--->1231--->1331

以此类推

为啥不从左向右遍历呢?因为如果从左向右遍历,那么左边的元素已经更新为第 i 行的元素了,而右边的元素需要的是第 i−1 行的元素。故从左向右遍历会破坏元素的状态。

代码(go)

func getRow(rowIndex int) []int {
    row := make([]int, rowIndex+1)
    row[0] = 1
    for i := 1; i <= rowIndex; i++ {
        for j := i; j > 0; j-- {
            row[j] += row[j-1]
        }
    }
    return row
}



3.移动零

题目:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 :

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

解题思路:

此题运用到双指针的思路,设置两个指针,a依次向右遍历,b记录非零元素的位置,当a遇到0,则跳过,继续向右遍历,遇到非0的元素则交换ab的值,并且b向右前进一步。

即遍历的时候每遇到一个 非0 元素就将其往数组左边挪,第一次遍历完后,b指针的下标就指向了最后一个 非0 元素下标。
第二次遍历的时候,起始位置就从 b开始到结束,将剩下的这段区域内的元素全部置为 0。

这个思路类似于快速排序,可以去小破站看一下视频

快速排序

                                                                                                                           (图片出自王尼玛)

代码(java)

class Solution {
	public void moveZeroes(int[] nums) {
		if(nums==null) {
			return;
		}
		//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
		int j = 0;
		for(int i=0;i<nums.length;++i) {
			if(nums[i]!=0) {
				nums[j++] = nums[i];
			}
		}
		//非0元素统计完了,剩下的都是0了
		//所以第二次遍历把末尾的元素都赋为0即可
		for(int i=j;i<nums.length;++i) {
			nums[i] = 0;
		}
	}
}	

这道题花费了我两小时的时间,因为我先了解了快速排序的原理,然后再学习了双指针的思想,最后卡到的最简单自增自减运算符上...

注意:

for循环的设计就是先执行循环体内的代码,然后再递增计数器 

所以其实在  for(int i=0;i<nums.length;++i)  这段语句中 无论是++i,还是i++都是可以运行的

然后在  nums[j++] = nums[i]这段语句中,其实j是先执行,然后再修改值的。以第二次循环为例,当i = 1的时候,遇到非0的元素,所有i 和 j 要交换元素 所以就是 num[0] = num[1] 然后j++ 变成1


4.区域和检索 -数组不可变

题目:

给定一个整数数组  nums,处理以下类型的多个查询:

  1. 计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的  ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )

示例 :

输入:
["NumArray", "sumRange", "sumRange", "sumRange"]
[[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]]
输出:
[null, 1, -1, -3]

解题思路:

这里用到前缀和思想,可以理解为高中学的数列

我们可以画一个sum[0]到sum[6]的数列,以【2,5】为例(此处的2,5是索引值

所以就是sum[6]-sum[2]

示例中的数组有6个元素,假如要计算索引2到5之间的总和(包含2到5),我们可以先计算索引为数组开始到5的总和减去数组开始到索引为2(不能包含索引2)

代码(java)

class NumArray {
    int[] sums;

    public NumArray(int[] nums) {
        int n = nums.length;
        sums = new int[n + 1];
        for (int i = 0; i < n; i++) {
            sums[i + 1] = sums[i] + nums[i];
        }
    }
    
    public int sumRange(int i, int j) {
        return sums[j + 1] - sums[i];
    }
}


5.第三大的数

题目:

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 1:

输入:[3, 2, 1]
输出:1
解释:第三大的数是 1 。

示例 2:

输入:[1, 2]
输出:2
解释:第三大的数不存在, 所以返回最大的数 2 。

示例 3:

输入:[2, 2, 3, 1]
输出:1
解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。

方式一:

Set 去重 + 排序

解题思路:

先使用 Set 对重复元素进行去重,然后对去重后的元素进行排序,并返回第三大的元素。

代码(Java)

class Solution {
    public int thirdMax(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int x : nums) set.add(x);
        List<Integer> list = new ArrayList<>(set);
        Collections.sort(list);
        return list.size() < 3 ? list.get(list.size() - 1) : list.get(list.size() - 3); 
    }
}

 HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。

 // 创建 HashMap 对象 Sites
        HashMap<Integer, String> Sites = new HashMap<Integer, String>();

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

使用一个增强型for循环遍历数组nums,将每个元素添加到set中。

for (int x : nums) set.add(x);

假如数组为【1,2,3】,那么执行

 return list.size() < 3 ? list.get(list.size() - 1) : list.get(list.size() - 3); 

这里的 list.size() - 3 实际上是 3 - 3 = 0,而 list.get(0) 会返回列表中的第一个元素,即 1

方式二:

有限变量 + 遍历

解题思路:(大家可以参考一下宫水三叶的解析

经典的找数组次大值的做法是使用两个变量 a 和 b 分别存储遍历过程中的最大值和次大值。

假设当前遍历到的元素为 x,当满足如下条件时,考虑更新 a 或者 b:

当 x>a 时,说明最大值被更新,同时原来的最大值沦为次大值。即有 b=a;a=x;
在条件 1 不满足,且有x>b 时,此时可以根据是否有「严格次大值」的要求,而决定是否要增加 x<a 的条件:
不要求为「严格次大值」:直接使用 x 来更新 b,即有 b=x;
当要求为「严格次大值」: 此时需要满足 x<a 的条件,才能更新 b。


回到本题,同理我们可以使用 a、b 和 c 三个变量来代指「最大值」、「严格次大值」和「严格第三大值」。

从前往后遍历 nums,假设当前元素为 x,对是否更新三者进行分情况讨论(判断优先级从上往下):

1. x>a,说明最大值被更新,将原本的「最大值」和「次大值」往后顺延为「次大值」和「第三大值」,并用 x 更新 a;
2. x<a 且 x>b,说明次大值被更新,将原本的「次大值」往后顺延为「第三大值」,并用 x 更新 b;
3. x<b 且 x>c,说明第三大值被更新,使用 x 更新 c。


起始时,我们希望使用一个足够小的数来初始化 a、b 和 c,因此需要使用 long 来进行代替。

返回时,通过判断第三大值是否为初始化时的负无穷,来得知是否存在第三大值。


 

代码(Java)

class Solution {
    long INF = (long)-1e18;
    public int thirdMax(int[] nums) {
        long a = INF, b = INF, c = INF;
        for (int x : nums) {
            if (x > a) {
                c = b; b = a; a = x;
            } else if (x < a && x > b) {
                c = b; b = x;
            } else if (x < b && x > c) {
                c = x;
            }
        }
        return c != INF ? (int)c : (int)a;
    }
}

❤️❤️❤️小郑是普通学生水平,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3-Vite-TypeScript:屏幕适配rem

① 基于rem 适配&#xff08;推荐&#xff0c;也是本篇要实现的方案&#xff09; 适用场景&#xff1a;不固定宽高比的Web应用&#xff0c;适用于绝大部分业务场景 ② 基于 scale 适配 适用场景&#xff1a;固定宽高比的Web应用&#xff0c;如大屏或者固定窗口业务应用 个人…

使用 openai 和 langchain 调用自定义工具完成提问需求

我们提供了一个函数&#xff0c;接受传入运算的字符串&#xff0c;返回运算的结果。 现在的需求是&#xff0c;我们问 gpt 模型&#xff0c;由于模型计算能力并不好&#xff0c;他要调用计算函数&#xff0c;根据计算结果&#xff0c;回答我们的问题。 使用 openai 实现&#…

资源|Python入门必看书籍,适合零基础小白,附PDF

小编为初学Python的朋友们汇总了7本零基础入门书籍&#xff0c;包括Python三剑客等&#xff0c;都是在编程届多年畅销的书籍&#xff0c;也是众多从业者的选择&#xff0c;全文详细介绍了书籍主要内容&#xff0c;有需要的宝子根据自身情况自取 需要书籍PDF的宝子评论区留言哦 …

Java每日一练_模拟面试题1(死锁)

一、死锁的条件 死锁通常发生在两个或者更多的线程相互等待对方释放资源&#xff0c;从而导致它们都无法继续执行。死锁的条件通常被描述为四个必要条件&#xff0c;也就是互斥条件、不可剥夺条件、占有并等待条件和循环等待条件。 互斥条件&#xff1a;资源不能被共享&#x…

MindMaster的学习(一)建立项目生成思维导图

MindMaster主要是用来做思维导图&#xff0c;当然也能直接生成PPT和甘特图&#xff0c;使用起来非常方便&#xff0c;简单分享下。 1.安装软件&#xff0c;这个随便搜一个破解版&#xff0c;有的就免安装&#xff0c;直接打开就能用。 2.我们新建一个导图&#xff0c;有空白模版…

认证!云起无垠成为人工智能产业发展联盟AIIA成员单位

近日&#xff0c;经人工智能产业发展联盟(AIIA)严格审核&#xff0c;云起无垠正式成为联盟成员单位。这一荣誉不仅肯定了云起无垠在技术方面的实力&#xff0c;更显示了对其未来发展的高度期待。 AIIA在国家发改委、科技部、工信部和网信办的指导下&#xff0c;由中国信息通信…

【iOS】iOS内存五大分区

iOS内存五大分区 总揽 iOS中&#xff0c;内存主要分为五大区域&#xff1a;栈区&#xff0c;堆区&#xff0c;全局区/静态区&#xff0c;常量区和代码区。总览图如下。 这个图我觉得更好记&#xff0c;因为下面是低地址&#xff0c;上面是高地址&#xff0c;是比较符合日常…

idea 2024 中文最新版破解激活永久(图文详细讲解教程)超级简单(亲测可用)

1.官网下载&#xff1a;下载地址 2.点击下载完成之后&#xff0c;找到下载路径&#xff0c;双击运行exe文件&#xff0c;进行安装 3.安装完成后&#xff0c;在桌面找到idea快捷方式&#xff0c;双击运行 4.此时是没有激活的&#xff0c;点击关闭窗口&#xff0c;然后退出程序 5…

nginx代理设置时能获取到源IP地址的方法

nginx通过http_x_forwarded_for限制来访IP示例_ngnix 根据header的x-forwarded-for限制接入-CSDN博客 名称ip客户端地址10.0.23.90nginx服务器地址110.0.202.48:18888&#xff0c;代理到10.0.204.82:8888nginx服务器地址210.0.204.82:8888&#xff0c;代理到10.0.204.82:8887后…

充电宝买多少毫安的好?选充电宝这几个关键点必看!

在如今这个电子设备不离手的时代&#xff0c;充电宝成为了我们生活中的必备品。然而&#xff0c;面对市场上琳琅满目的充电宝&#xff0c;选择合适容量的充电宝却让许多人感到困惑。充电宝买多少毫安的好&#xff1f;这可不是一个简单的问题。容量太小&#xff0c;无法满足我们…

20240802 每日AI必读资讯

&#x1f310;太离谱&#xff01;曝GPT-4o mini没做安全测试就开庆功会&#xff01; - OpenAI曾向美国政府承诺&#xff0c;将严格对其前沿的突破性技术进行安全测试&#xff0c;以确保AI不会造成损害&#xff0c;比如教用户制造生化武器或帮助黑客开发新型网络攻击。 - Open…

canvas根据图片生成粒子动画

canvas根据图片生成粒子动画 效果展示: canvas根据图片生成粒子动画效果 注意: js和css的引入 id: cartoonDot-img对应的是被 拷贝的图像,后期要替换的 粒子图像就在这 min.js 地址 HTML代码块 <!DOCTYPE html> <html><head><meta charset=&quo…

面向对象编程在Python中的应用

引言 面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;是一种程序设计范式&#xff0c;它使用“对象”来设计软件。在Python中&#xff0c;OOP提供了一种结构化的方式来组织代码&#xff0c;使得程序更加易于理解和维护。本文将介绍一些基本的面向对象编…

洗地机哪个品牌好用?智能洗地机品牌排行榜揭晓

在追求家居清洁智能化的今天&#xff0c;洗地机品牌众多&#xff0c;选择一款好用且智能的洗地机成了许多家庭的关注点。本文精心揭晓智能洗地机品牌排行榜&#xff0c;为大家精选出市场上性能卓越、用户口碑极佳的品牌&#xff0c;如滴水、以内、希亦等&#xff0c;它们凭借创…

电池数据巡检时发现的数据问题处置措施

电池监控系统在日常使用中需要关注电压不均告警和内阻不均告警&#xff0c;对偏差大的单体电池核实处理。 一、电池单体电压偏差 出现电池单体电压偏差有两种情况&#xff0c;一种是电池故障&#xff0c;另一种是电池单体采集模块故障。现场需要用万用表对异常单体电压进行测量…

轻松入门Linux—CentOS,直接拿捏 —/— <5>

一、Linux常用工具 1、tar打包命令详解 当 tar 命令用于打包操作时&#xff0c;该命令的基本格式为&#xff1a; tar [选项] 源文件或目录 常用选项&#xff1a; 1.1 打包文件 例如&#xff0c;我有几个文件&#xff0c;将他们打包成一个文件&#xff0c;以tar结尾的后缀名 …

新手小白,如何新建一个springboot的web项目?

第一步&#xff1a;打开软件&#xff0c;点击file&#xff0c;点击new 然后选择module&#xff0c;在右侧选择springboot 第二步&#xff1a;选择配置和JDK以及java版本 ①选择maven类型 ②选择JDK1.8版本 ③选择java8版本 ④选择jar包类型 如果不知道或者找不到配置8版本&…

【JVM】类加载器和双亲委派模型

什么是类加载器 如果想要了解什么是类加载器就需要清楚一个Java文件是如何运行的。我们可以看下图&#xff1a; 首先要知道操作系统是不能直接运行Java文件的&#xff0c;所以就需要通过JVM将Java文件转换为操作系统可以运行的文件类型&#xff0c;步骤如下&#xff1a; 类加…

lua学习(1)

1. lua 字符串 单个引号和双引号都可变量的定义默认是全局的删除一个变量将其赋值为nil即可 如&#xff1a; bnilnil还可以对表中的数据进行删除&#xff0c;也可删除一个表只要变量不是nil&#xff0c;变量即存在标识符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后&am…

网安加·百家讲坛 | 高明:模糊测试技术在车联网安全性评估中的应用

作者简介&#xff1a;高明&#xff0c;信息安全硕士&#xff0c;10年以上软件安全开发和产品架构设计经验。成功主导多个模糊测试和车联网安全相关的产品研发与项目实施&#xff0c;并参与网络安全产品相关行业标准的编写。擅长产品规划和敏捷项目管理&#xff0c;持有PMP、PgM…